思路:from:http://blog.csdn.net/cc_again/article/details/12174269
下面先介绍一种运算:
把xx右移一位的同时,把最后一位数字放到第一位上。
例如 n = 3; 那么编号从0开始的话,
0(000) -->0(000) -->0(000) -->0(000)
1(001) -->4(100) -->2(010) -->1(001)
2(010) -->1(001) -->4(100) -->2(010)
3(011) -->5(101) -->6(110) -->3(011)
4(100) -->2(010) -->1(001) -->4(100)
5(101) -->6(110) -->3(011) -->5(101)
6(110) -->3(011) -->5(101) -->6(110)
7(111) -->7(111) -->7(111) -->7(111)
对于序数为偶数的牌,也就是最低位为0的牌,直接循环右移一位,相当于除以二,这样就凑出了第一堆,
对于序数为奇数的牌,最低位为1,循环右移一位后,相当于除二后加了2^(n-1),也就是加了前面偶数堆的长度。
这样就把位置为i的牌,经过一次切牌后的位置算出来了。
对于抑或可以先移位然后所有位一起抑或,但是右移操作最多只有n次,超过n次的话,就重复了,所以可以先右移n次,每右移一次(切牌)有两种方式抑或0或者1,这样就得到了一个长度为n的o、1抑或串,也就是切牌方式。
枚举开始点,右移次数k,将X,Y右移K位,
由于a^b=c可以推出a^c=b,所以把X抑或A与Y抑或B比较,判断是否相同(相同表示序号为X的牌和序号为Y的牌可以经过相同的切牌方式得到位置A和B)。
代码如下:
import java.math.*;
import java.util.*;
public class Main
{
static int n;
static Scanner cin = new Scanner(System.in);
static BigInteger rot(BigInteger x)
{
BigInteger s = x.and(BigInteger.valueOf(1));
return x.shiftRight(1).or(s.shiftLeft(n-1));
}
public static void main(String[] args)
{
int t = cin.nextInt(), K = 0;
while(++K<=t)
{
n = cin.nextInt();
BigInteger A = cin.nextBigInteger(), X = cin.nextBigInteger();
BigInteger B = cin.nextBigInteger(), Y = cin.nextBigInteger();
A = A.add(BigInteger.valueOf(-1));
B = B.add(BigInteger.valueOf(-1));
X = X.add(BigInteger.valueOf(-1));
Y = Y.add(BigInteger.valueOf(-1));
String ans = "No";
for(int i = 0; i <= n; ++i)
{
A = rot(A);
B = rot(B);
BigInteger dx = A.xor(X);
BigInteger dy = B.xor(Y);
if(dx.compareTo(dy) == 0)
{
ans = "Yes";
break;
}
}
System.out.println("Case "+ K + ": " + ans);
}
}
}