Codeforces Round #554 (Div. 2) 1152B - Neko Performs Cat Furrier Transform

笔记:
1.
2^i: 10000000
2^i-1:1111111
判断x是否是2^i:
1.找到位数范围,1e6为0~ 20,1e9为0~30,因为1e6约等于2^ 20,1e9约等于2^30
2.循环判断是否可以为1<<i,O(1)复杂度
判断x是否为2^i-1 ,先加一,在判断是否为2^i
2.
判断x的第i位数字,x>>i,从左往右找到x的第一个1,就是找到x的最大位i为1
从i的最大位20开始递减,x>>i是否为1。
3.
两个操作轮流来,并计数,那么只需要在循环里每次只计数一次
奇数次执行A操作,偶数次执行B操作即可。
不断判断x是否完成,直到完成。
第一种方法: 如果x为:1000那么x异或0111得到1111,即找到x的最大位1的位置r,x(2i-1)
不是的话,比如x:1011,那么找到x的最大位1的位置r,x异或1111得到0100,消去了i位1
即x(2(r+1)-1),这样不断消去1,x不断缩小直到0,不会回溯,有限次数小于20.
r+1可以在判断不是的情况时r++这样保持统一公式。

第二种方法:直接找到x的最大位1的位置r,x异或1111得到0100,消去了i位1
即x(2(r+1)-1),这样不断消去1,x不断缩小直到0,不会回溯,有限次数小于20.

#include<bits/stdc++.h>
using namespace std;
vector<int> ans;
int x,cnt;
/*
#include<bits/stdc++.h>
using namespace std;
vector<int> ans;
int x,cnt;
/*
bool complete(int x)
{
    x++;
    while(x%2!=1)
    {
        x/=2;
    }
    return x==1;
}*/
/*
2^i: 10000000
2^i-1:1111111
判断x是否是2^i:
1.找到位数范围,1e6为0~20,1e9为0~30,因为1e6约等于2^20,1e9约等于2^30
2.循环判断是否可以为1<<i,O(1)复杂度
判断x是否为2^i-1,先加一,在判断是否为2^i
*/
bool complete(int x)
{
    x++;
    for(int i=0;i<=20;i++)
    {
        if(x==(1<<i))
            return true;
    }
    return false;
}
/*
判断x的第i位数字,x>>i,从左往右找到x的第一个1,就是找到x的最大位i为1
从i的最大位20开始递减,x>>i是否为1。
*/
int MSB(int x)
{
    for(int i=20;i>=0;i--)
    {
        if((x>>i)==1)
            return i;
    }
    return -1;
}
int main()
{
    cin >> x;
    /*
    两个操作轮流来,并计数,那么只需要在循环里每次只计数一次
    奇数次执行A操作,偶数次执行B操作即可。
    不断判断x是否完成,直到完成。
    如果x为:1000那么x异或0111得到1111,即找到x的最大位1的位置r,x^(2^i-1)
    不是的话,比如x:1011,那么找到x的最大位1的位置r,x异或1111得到0100,消去了i位1
    即x^(2^(r+1)-1),这样不断消去1,x不断缩小直到0,不会回溯,有限次数小于20.
    r+1可以在判断不是的情况时r++这样保持统一公式。
    */
    while(!complete(x))
    {
        cnt++;
        if(cnt%2==1)
        {
            int r=MSB(x);
            //if(x!=(1<<r)) r++;
            r++;
            x=x^((1<<r)-1);
            ans.push_back(r);
        }
        else
            x++;
    }
    if(cnt==0)
        cout << 0 <<endl;
    else
    {
        cout << cnt << endl;
        for(int i=0;i<ans.size();i++)
        {
            cout << ans[i] << " ";
        }
        cout << endl;
    }
    return 0;
}

B. Neko Performs Cat Furrier Transform
time limit per test1 second
memory limit per test256 megabytes
inputstandard input
outputstandard output
Cat Furrier Transform is a popular algorithm among cat programmers to create longcats. As one of the greatest cat programmers ever exist, Neko wants to utilize this algorithm to create the perfect longcat.

Assume that we have a cat with a number x. A perfect longcat is a cat with a number equal 2m−1 for some non-negative integer m. For example, the numbers 0, 1, 3, 7, 15 and so on are suitable for the perfect longcats.

In the Cat Furrier Transform, the following operations can be performed on x:

(Operation A): you select any non-negative integer n and replace x with x⊕(2n−1), with ⊕ being a bitwise XOR operator.
(Operation B): replace x with x+1.
The first applied operation must be of type A, the second of type B, the third of type A again, and so on. Formally, if we number operations from one in the order they are executed, then odd-numbered operations must be of type A and the even-numbered operations must be of type B.

Neko wants to produce perfect longcats at industrial scale, thus for each cat Neko only wants to perform at most 40 operations. Can you help Neko writing a transformation plan?

Note that it is not required to minimize the number of operations. You just need to use no more than 40 operations.

Input
The only line contains a single integer x (1≤x≤106).

Output
The first line should contain a single integer t (0≤t≤40) — the number of operations to apply.

Then for each odd-numbered operation print the corresponding number ni in it. That is, print ⌈t2⌉ integers ni (0≤ni≤30), denoting the replacement x with x⊕(2ni−1) in the corresponding step.

If there are multiple possible answers, you can print any of them. It is possible to show, that there is at least one answer in the constraints of this problem.

Examples
inputCopy
39
outputCopy
4
5 3
inputCopy
1
outputCopy
0
inputCopy
7
outputCopy
0
Note
In the first test, one of the transforms might be as follows: 39→56→57→62→63. Or more precisely:

Pick n=5. x is transformed into 39⊕31, or 56.
Increase x by 1, changing its value to 57.
Pick n=3. x is transformed into 57⊕7, or 62.
Increase x by 1, changing its value to 63=26−1.
In the second and third test, the number already satisfies the goal requirement.

官方题解:

1152B - Neko Performs Cat Furrier Transform
There are various greedy solutions available. I’ll only cover one of them.

We’ll perform a loop as of following:

If x≤1, stop the process (since it’s already correct).
If x=2m (m≥1), perform operation A with 2m−1. Obviously, the resulting x will be 2m+1−1, which satisfies the criteria, so we stop the process.
Otherwise, let’s denote MSB(x) as the position/exponential of the most significant bit of x (for example, MSB(4)=MSB(7)=2). We’ll perform operation A with 2MSB(x)+1−1. If x after this phase is not a valid number, we’ll then perform operation B and return to the beginning of the loop.
This will never take more than 40 queries, since each iteration will be guaranteed to remove the most significant bit (and it would never return in later steps), and x can only have at most 20 bits initially.

Also, one can solve this problem by performing a BFS with traceback. However, this is not my intended solution, since the implementation is too hard for a Div-2B.

#pragma comment(linker, "/stack:247474112")
#pragma GCC optimize("Ofast")

#include <bits/stdc++.h>
using namespace std;

#define endl '\n'

int x;

bool isCompletion(int z) {
	int bitval = 0;
	z += 1; while (z % 2 == 0) {z /= 2; bitval++;}
	return (z == 1);
}

int MSB(int z) {
	for (int i=20; i>=0; i--) {
		if ((z >> i) & 1) return i;
	}
	return -1;
}

void Input() {
	cin >> x;
}

void Solve() {
	int i = 0; vector<int> xorCmd;
	while (isCompletion(x)) {
		i = i + 1;
		if (i % 2 == 0) {x++; continue;}
		int r = MSB(x);
		if ((1 << r) != x) r++;
		x = (x ^ ((1 << r) - 1)); xorCmd.push_back(r);
	}
	cout << i << endl;
	for (auto z: xorCmd) cout << z << " "; cout << endl;
}

int main(int argc, char* argv[]) {
	ios_base::sync_with_stdio(0);
	cin.tie(NULL); Input(); Solve();
	return 0;
}

猜你喜欢

转载自blog.csdn.net/w1304636468/article/details/89514157