Neko Performs Cat Furrier Transform CodeForces - 1152B 二进制思维题
Neko Performs Cat Furrier TransformCodeForces - 1152B
题目大意:给你一个x,在40步操作以内把x变成2m−1,m为非负整数。对于每步操作,奇数步可以在(0<=n<=30)中挑选一个n,将x⊕(2n−1),而偶数步将x++。输出操作步数,以及在每个奇数步异或的n,多个答案,输出任一答案,保证至少有一个答案。
一开始傻逼了,真的照题意所说的去写了一个深搜,果断超时了。其实每个奇数步也是异或一个二进制全1的数,那我们就直接把x尾部连续0部分,全部异或为1,那么在偶数步加1的话,又会往前进位填补前面的0(如果有的话0),然后再继续把x尾部连续0部分,全部异或为1,直到x为二进制全1即可。
就比如x=80,二进制为1010000,我们第一步先异或个24-1=15即1111,x就变成了95=1011111,然后第二步x++,x就成了96=1100000,第三步在异或个25-1=31即11111,x变成了127=1111111,结束。
因为1e6,最多就220左右,肯定不会超出40步。而取得末尾连续0部分正是树状数组里的那个x&(-x),不懂的可以去了解下。
1 #include<cstdio> 2 #include<vector> 3 #include<cmath> 4 #include<map> 5 using namespace std; 6 map<int,int> m; 7 vector<int> ans; 8 int main() 9 { 10 int cf2=1; 11 //把终止情况,2^i-1标记一下 12 m[0]=1; 13 for(int i=1;i<=30;i++) 14 { 15 cf2<<=1; 16 m[cf2-1]=1; 17 } 18 int x,step=0; 19 scanf("%d",&x); 20 while(!m[x]) 21 { 22 step++; 23 if(step&1) 24 { 25 int y=x&(-x),n=0; 26 x^=(y-1); 27 while(y) 28 { 29 n++; 30 y>>=1; 31 } 32 //y=2^(n-1) 33 ans.push_back(n-1); 34 } 35 else 36 x++; 37 } 38 printf("%d\n",step); 39 for(int i=0;i<ans.size();i++) 40 { 41 if(i) 42 putchar(' '); 43 printf("%d",ans[i]); 44 } 45 printf("\n"); 46 return 0; 47 }
我太难了~给个三连吧,亲~~~