• 【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
  • 相关阅读:
    uboot nand erase 的显示错误修复
    Sougo for linux install.
    S3C6410移植uboot2010.3(2)基本的启动信息修改
    S3C6410移植uboot2010.3(4)uboot的dnw功能添加
    S3C6410移植uboot2010.3(3)正常化配置
    ubuntu乱码修复
    应老婆点(20070705 13:11:34)(新浪)
    克己慎独 2008923 13:32:00 (21ic)
    信任(20061229 14:16:32)(新浪)
    不要轻易承诺 2008926 14:42:00 (21ic)
  • 原文地址:https://www.cnblogs.com/zsnuo/p/7282737.html
Copyright © 2020-2023  润新知