B. Neko Performs Cat Furrier Transform---异或的性质运用--Codeforces Round #554 (Div. 2)

Neko Performs Cat Furrier Transform

time limit per test 1 second
memory limit per test 256 megabytes

题目链接http://codeforces.com/problemset/problem/1152/B

B. Neko Performs Cat Furrier Transform---异或的性质运用--Codeforces Round #554 (Div. 2)_第1张图片
B. Neko Performs Cat Furrier Transform---异或的性质运用--Codeforces Round #554 (Div. 2)_第2张图片


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 
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;
}

你可能感兴趣的:(Codeforces)