Codeforces Round #554 (Div. 2) B. Neko Performs Cat Furrier Transform(思维题+log2求解二进制位数的小技巧)

传送门

 

题意:

  给出一个数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\n",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 }
View Code

 

有关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<<"位\n";

第四行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 位;

posted @ 2019-04-25 19:52  HHHyacinth  阅读(327)  评论(1编辑  收藏  举报