【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 }
View Code
posted @ 2017-08-03 23:54  Zsnuo  阅读(193)  评论(0编辑  收藏  举报