[タイトルの説明]
最初、アリスとボブはそれぞれ整数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);
}
}
}