第12回ブルーブリッジカップジャワ州大会グループAの質問:XORシーケンス

[タイトルの説明]
最初、アリスとボブはそれぞれ整数aとbを持ち、長さnのシーケンスが与えられています。aとbの初期値は両方とも0です。アリスとボブが交代で操作し、アリスが最初に開始し、各ステップで2つのオプションのいずれかを選択できます。
オプション1:シーケンスからXを選択し、番号をアリスにXORします。
オプション2:シーケンスからXを選択します;XORボブの番号。
各番号Xiは1回しか使用できません。各番号を1回使用すると、ゲームオーバーになります。数字が最も大きい側が勝ち、2つの側は同じ番号を持ちます。これは引き分けを意味します。
どちらの側も、最適な戦略を採用し、誰が勝つかを尋ねるのに十分賢いです。

[入力形式]
各評価ケースには、複数のクエリセットが含まれています。クエリは互いに独立しています。
入力の最初の行には、クエリの数を表す整数Tが含まれています。
次の各T行には、一連のクエリが含まれています。i番目の行の最初の整数nはシーケンスの長さを表し、次のn個の整数X1、X2、...Xmはシーケンスの各数値を表します。

【出力形式】
各グループの問い合わせの回答に対応するT行を順番に出力します。
各行には整数1、0、または-1が含まれており、それぞれアリスが勝ち、引き分け、または負けていることを示します。

【サンプル入力】 411 1 0 2 2 1
7 992438 1006399 781139 985280 4729 872779 563580



【サンプル出力101
1


[評価ケースのスケールと規則]
すべての評価ケースで、1≤T≤200000、1≤∑Ti = 1ni≤200000、0≤Xi<220。


【問題解決のアイデア】
参考:このブログ

まず第一に、なぜゲームの終了は数字のシーケンスを与えられて決定されるのですか?
勝利とは、Aがどのように反応しても、Aが特定の戦略を採用できること、Aが勝つことを保証すること、
Bが勝利することは、Aが何に反応しても、Bが特定の戦略を採用できること、Bが勝利できることを保証することを意味します。 .Win;
XORの場合:0^X-Xを保持;1^ X-Xを反転;
偶数回の反転は元の状態に戻ります。つまり、偶数回の1のXORは変更されません。

最後の2つの結果の数値A^B = a^b^sum。ここで、sumは、指定されたシーケンス内のすべての数値のXOR合計ですsum = X1^X2^...Xni。したがって、同数の場合(つまり、A = B)、A ^ B = 0(つまり、sum = 0)です。

ここで、合計!= 0を検討します。これは、ビット単位のXORであり、AとBの2つの値のサイズが最後に比較されるため、バイナリの最上位ビットが等しい場合は、次に上位のビットを比較してから、結果が判断できるまで比較します。

int配列res[i]は、バイナリのi番目のビットの1の数を表すために使用されます。特定のビットのres [i]が奇数の場合、つまり、 aおよびbとXORされたビット。たとえば、5つの1があります。0は状態を変更しないため、その(a、b)の状態遷移プロセスは次のようになります。(0、0)->フリップ->描画->フリップ->ドロー->フリップ、つまりドローで(0、0)または(1、1)のいずれかで、アリスとボブの間で最後のフリップ(つまり最後の1)を持っている人がゲームに勝ちます!!

では、最後の1つをどのようにオンにしますか?0は数字のサイズを変更しないため、0が使用されようとしていますが、これは自分自身に「さようなら」を与えることと同じです。または、上記の5つの1の状況を考えてみましょう。最後のフリップの前に偶数の0が挿入された場合(場所に関係なく)、1の最後のフリップ右がアリスに到達し、最初のプレーヤーが勝ちます。最後のフリップの前の場合(位置に関係なく)どの位置に)奇数の0を挿入すると、1の最後の右フリップがバックハンドのボブに到達し、バックハンドが勝ちます。

アリスとボブはどちらも「十分に賢い」ので、奇数の1に直面して、ボブは生き残るチャンスがあるように「スナッチ0」に行かなければならず、アリスも対処するために「スナッチ0」をしなければなりません。それで、最後の右フリップが戻るようにあなた自身の手で、0の数が制限されているので、勝つか負けるかの最終決定は0のパリティです。

したがって、桁のres [i]が偶数の場合、ゲーム結果のこの桁は等しくなければならず、次の桁が考慮されます。i番目の桁の1の数が1の場合、最初のムーバー勝つ必要があります(出力: "1"); i番目の位置の1の数が1より大きい奇数で、0の数が偶数の場合、最初の手が勝ちます(出力: "1") ; i番目の位置の1の数が1奇数の数より大きい場合、0の数が奇数の場合、秒針が勝ちます(出力: "-1")。


Javaコード:

import java.util.ArrayList;
import java.util.Scanner;

public class Main {
    
    
    public static void main(String[] args) {
    
    
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        //该ArrayList用来暂存每次询问结果,待最后一次询问结束再统一输出
        ArrayList<Integer> res = new ArrayList<>();
        //n次询问
        for (int i = 0; i < n; i++) {
    
    
            int[] weis = new int[24]; //该数组用于存储二进制形式下每一位1的数量
            int m = scanner.nextInt();
            //长度为m的数列转为二进制并处理
            for (int j = 0; j < m; j++) {
    
    
                long l = scanner.nextLong();
                String string = Long.toBinaryString(l); //转为二进制
                String reStr = new StringBuilder(string).reverse().toString(); //反转,即高低位反转,便于存储与后面处理
                //判断二进制形式下每一位是否为1
                for (int k = 0; k < reStr.length(); k++) {
    
    
                    if (reStr.charAt(k) == '1') weis[k]++;
                }
            }
            //对每次询问后每一位中1的个数判断从而得到结果,并将结果先暂时存储在ArrayList-res中
            for (int j = weis.length - 1; j >= 0; j--) {
    
    
                if (weis[j] % 2 == 0 && j == 0) {
    
    
                    res.add(0);
                    break;
                }else if (weis[j] % 2 == 0){
    
    
                    continue;
                }
                if (weis[j] == 1){
    
    
                    res.add(1);
                    break;
                }else if (weis[j] % 2 == 1 && (m - weis[j]) % 2 == 0){
    
    
                    res.add(1);
                    break;
                }else if (weis[j] % 2 == 1 && (m - weis[j]) % 2 == 1){
    
    
                    res.add(-1);
                    break;
                }
            }
        }
        //输出结果
        for (int x : res){
    
    
            System.out.println(x);
        }
    }
}

おすすめ

転載: blog.csdn.net/m0_46653805/article/details/123666722