time limit per test 1 second memory limit per test 256 megabytes
题目链接http://codeforces.com/problemset/problem/1152/B
emmm,题目大意:给你一个数n,让你对他进行t次操作使得它的值为2x-1,你第一次只能将它异或2x-1,第二次只能对它+1,第三次…让你求t,并输出每个x;
题目有点想法,如果对异或不太熟悉的人可能有点迷,但实际上我们可以通过第一个样例来看:
首先我们将它(39)化为二进制:100111 异或会使得相同的变为0,不相同的变为1,而2x-1化为二进制则是1111111…(x-1个)。也就是说我们异或的时候会使得x-1位及以下的反转。
那么题目的意思就是让你在二进制的数据下降n的每位变成1。
那么也就好做了,我们对n从高位一位位地找下去,如果该位置为1,则继续找,否则我们就将它异或2i+1-1(i为二进制下的第i位)。至于第二个操作就不用管了,他是固定的操作。
当然我是先将它异或了一个2p-1(p为n的二进制下的长度)。这个完全可以删掉。。
以下是AC代码:
#include <bits/stdc++.h> using namespace std; int ok(int x) { while (x){ if (x%2==0) return 0; x>>=1; } return 1; } int a[60],b[60]; int pow(int x,int y) { int ans=1; for (int i=1; i<=y; i++) ans*=x; return ans; } int main() { int n; scanf ("%d",&n); if (ok(n)){ printf ("0\n"); return 0; } else { int ans=0,nb=0; while (!ok(n)){ ans++; int cp=n,op=0; if (ans&1) { if (ans==1){ while (cp) cp>>=1,op++; n^=pow(2,op)-1; a[++nb]=op; } else { int sb; memset(b,0,sizeof(b)); while (cp) b[op++]=cp%2,cp>>=1; while (!b[op]) op--; for (int i=op; i>=0; i--) if (!b[i]){ sb=i+1; break; } n^=pow(2,sb)-1; a[++nb]=sb; } } else n++; } printf ("%d\n",ans); if (ans&1) for (int i=1; i<=ans/2+1; i++) printf ("%d ",a[i]); else for (int i=1; i<=ans/2; i++) printf ("%d ",a[i]); printf ("\n"); } return 0; }