题意:
给出一个数x,有两个操作:
①:x ^= 2k-1;
②:x++;
每次操作都是从①开始,紧接着是②
①②操作循环进行,问经过多少步操作后,x可以变为2p-1的格式?
最多操作40次,输出操作数和所有操作中步骤①的操作数的k;
我的思路:
操作①每次都是异或 (k-1) 个1;
我们最终的结果是将 x 变为(p-1)个1;
那么,我们只要每次异或操作都将x中最高的0位变为1;
因为x最多只有20位,所以,完全可以在40个操作内将x变为(p-1)个1;
例如:
7654321(位置)
(1001011)2
①第一步,找到最后一个0的位置6,异或(1<<6)-1
(1001011)^( 111111)=(1110100)
(1110100)+1=(1110101)
接着查找最后一个0的位置4(重复步骤①),异或(1<<4)-1
(1110101)^(1111)=(1111010)
(1111010)+1=(1111011)
接着执行步骤①②,直到满足条件 (有可能不执行x++操作)
AC代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<cmath> 4 using namespace std; 5 6 int x; 7 int a[50]; 8 9 int F() 10 { 11 for(int i=(int)log2(x);i >= 0;--i) 12 if(!((1<<i)&x)) 13 return i+1; 14 } 15 void Solve() 16 { 17 //need=x的二进制中0变为1对应的10进制数 18 //例如:x=(1010),need=(1111) 19 int need=pow(2,(int)log2(x)+1)-1; 20 int ans=0; 21 while(x != need) 22 { 23 int k=F();//x的k-1位置为最高位的0(从0开始) 24 a[++ans]=k; 25 x ^= (1<<k)-1;//将最高位的0变为1 26 if(x == need) 27 break; 28 ans++; 29 x++; 30 } 31 printf("%d ",ans); 32 for(int i=1;i <= ans;i+=2) 33 printf("%d ",a[i]); 34 } 35 int main() 36 { 37 scanf("%d",&x); 38 Solve(); 39 40 return 0; 41 }
有关log2(x)求解x转化为二进制位数的小技巧:
这里要手动艾特我家小花猪,要不然,我还不知道,还有这操作呢QWQ;
一直以来,求解十进制数x转化为二进制数的位数我都是这么操作的:
1 int x; 2 cin>>x; 3 int tot=30; 4 for(;!((1<<tot)&x);tot--); 5 cout<<"共"<<tot+1<<"位 ";
第四行for()代码,完全可以用个公式一行搞定:
tot=log2(x)+1;
来,分析一下:
假设log2(x)=y;
如果x为2的幂,假设x=2k,那么,y=k;
反之,即2k < x < 2k+1,y = k;
不管如何,x转化成二进制的位数为 k+1 位,即 log2(x)+1 位;