【SRM-09 B】撕书II
Description
琉璃手头有一黑一白两本魔法书,一本是《缟玛瑙的不在证明》,另一本是《白色相簿1.5》。传说同时打开这两本书会有奇怪的事情发生。琉璃打开一看,果然非常奇怪:两本书上都各自写着一个正整数(可能他买到盗版了),分别是a和b。试图撕书的汀想借过来看看,但琉璃只告诉了他这俩数加起来的值x和异或起来的值y。汀发现有很多种(a,b)满足琉璃告诉他的信息...你能帮他算出来有多少种吗?
Input
两个用空格隔开的整数x和y。
Output
一个整数,表示有多少种情况。
Sample Input
9 5
Sample Output
4
写了比较详细的代码注释……
(写题解的时候突然发现自己的写法又蠢又啰嗦啊,但写都写了就随意发咯(逃),大家看着玩就好了QAQ
1 //比赛完葱神提到了异或的一条很重要的性质:异或是不进位加法 2 //另,ll很重要!!!!! 3 #include<cstdio> 4 #include<algorithm> 5 #include<cstring> 6 #include<iostream> 7 #define ll long long 8 using namespace std; 9 ll x,y,t,tt,ans,nn; 10 int cnt,now,p[150]; 11 bool f[150],fl; 12 ll read() 13 { 14 ll x=0,f=1;char c=getchar(); 15 while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} 16 while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();} 17 return x*f; 18 } 19 int main() 20 { 21 x=read();y=read();t=y; 22 while(t)//一位一位拆了y 23 { 24 if(t&1)nn++,f[now]=true;//统计1出现的次数,并将其位置打上标记 25 else p[++cnt]=now;//记录0出现的位置 26 t>>=1;now++; 27 } 28 if(x==y){printf("%lld",((ll)1<<nn)-2);return 0;} 29 //如果x==y,则说明a+b时没有出现进位的情况; 30 //此时统计1出现的次数nn,则a和b总共有2^nn个组合; 31 //其中有2个组合为0和x,不满足题意,减掉之后直接输出结果 32 while((ll)1<<now<x)p[++cnt]=now,now++;//将0的位置补满直到1<<now>x为止 33 nn=(ll)1<<nn; 34 //y中1的位置上,a和b必然是一个为0,一个为1 35 //所以在确定y中0的位置上a、b相同位置上的数之后,会增加2^nn个答案 36 //接下来要确定y中0的对应位置上a、b的数 37 //枚举y中0的位置p,强制位置p上a、b皆为1,位置<p的位置上a、b皆为0,这是为了防止重复 38 for(int i=1;i<=cnt;i++) 39 { 40 t=((ll)1<<(p[i]+1))+y;//先加上强制a、b位置p[i]上皆为1的值 41 if(t>x)break;//大于x,直接跳出循环 42 fl=false;now=0;tt=x-t; 43 if(tt%2)continue; 44 //每一次强制a、b某位置上为1都会同时增加a、b的值,所以差值一定为偶数 45 //根据差值可以推断出哪个位置上a、b同为1 46 tt>>=1; 47 while(tt) 48 { 49 if((tt&1)==0)//a、b当前位置上同为0,直接跳过 50 { 51 tt>>=1;now++; 52 continue; 53 } 54 if(f[now]||now<=p[i]){fl=true;break;} 55 //如果需要a、b同为1的位置小于等于p[i]或该位置上y==1,不合法,直接跳出循环 56 tt>>=1;now++; 57 } 58 if(!fl)ans+=nn;//根据枚举出来的状态直接更新答案 59 } 60 printf("%lld",ans); 61 return 0; 62 }