题意:给定2^N张扑克牌,重新洗几次牌后,问是否存在a位置上为x,b位置上为y的情况。每次洗牌的规则是原奇数位置扑克在前原偶数位置在后,或者原偶数位置扑克在前原奇数位置在后。
分析:这道题就是找规律,比赛的时候只关注了每个位置扑克牌的变化情况了,如果关注每张扑克牌的位置变化,就会发现两种规则都是有规律的。
将每张扑克牌的牌面-1,位置也-1,这样从0开始,更符合逻辑。如果洗牌时原奇数位置扑克在前原偶数位置在后,那么观察某张扑克的位置的二进制变化就知道,是右移一位左边异或1;反过来,是右移一位左边异或0.
那么好办了,如果是按照统一规则变化的扑克牌,两张扑克牌的变化i步必定都是右移i位再异或上同一个数。这样我们解这道题时可以模拟这样一个变化:初始时刻,x在位置x上,y在位置y上,同时右移i位并并异或上某个相同数后,的到了两个数的位置a和b(程序实现要参考异或性质反过来求这个数),那么说明这i步变化是相同的,即存在一种情况使得最后a位置上为x,b位置上为y。
(这次说的够清楚了,以前写博客写的好少,哈哈,得坚持这样写。)
Java代码:
import java.math.BigInteger;
import java.util.Scanner;
public class Main{
private static int N;
private static BigInteger a, b, x, y;
private static BigInteger shift(BigInteger t) {
BigInteger s = t.and(BigInteger.ONE);
return t.shiftRight(1).or(s.shiftLeft(N-1));
}
private static boolean Judge() {
for(int i = 0; i < N; ++i) {
x = shift(x); y = shift(y);
if(x.xor(a).equals(y.xor(b)))
return true;
}
return false;
}
public static void main(String[] args) {
Scanner cin = new Scanner(System.in);
int T = cin.nextInt(), kase = 0;
while((T--) > 0) {
N = cin.nextInt();
a = cin.nextBigInteger().subtract(BigInteger.ONE);
x = cin.nextBigInteger().subtract(BigInteger.ONE);
b = cin.nextBigInteger().subtract(BigInteger.ONE);
y = cin.nextBigInteger().subtract(BigInteger.ONE);
if(Judge()) System.out.println("Case " + (++kase) + ": Yes");
else System.out.println("Case " + (++kase) + ": No");
}
}
}