Codeforces Round #730 (Div. 2) D. RPD and Rap Sheet (交互,从easy到hard)

Posted issue是fw

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Codeforces Round #730 (Div. 2) D. RPD and Rap Sheet (交互,从easy到hard)相关的知识,希望对你有一定的参考价值。

easy

hard

题意

已知密码是 k k k进制数,在十进制下是 [ 0 , n − 1 ] [0,n-1] [0,n1]之间,你有至多 n n n次机会猜测这个数

设你猜的数字是 y y y,如果答案正确,系统会返回 1 1 1

如果答案错误,系统将返回 0 0 0,而且会修改密码为 z z z

x ⊕ z = y x\\oplus z=y xz=y

其中 x x x是上一次的密码, z z z是新密码, y y y是你本轮猜测的数

异或操作,是把 x , z x,z x,z转化为 k k k进制,对应位做模 k k k意义下的加法运算

(你只需要给出当前的密码而不是初始密码!!!)


e a s y easy easy

此时 k = 2 k=2 k=2,那么 z = x ⊕ y z=x\\oplus y z=xy

考虑枚举每个数为初始密码

比如我认为 i i i是初始密码,那么经过我之前的一系列操作,现在密码变成什么样了呢??

设我之前猜测的数是 y 1 , y 2 . . . y k y_1,y_2...y_k y1,y2...yk,那么现在密码就应该是 r e s = y 1 ⊕ y 2 . . . ⊕ y k ⊕ i res=y_1\\oplus y_2...\\oplus y_k \\oplus i res=y1y2...yki

于是我们猜测当前密码是 r e s res res,如果初始密码真的是 i i i我们就应该猜对了

否则,我们确信初始密码并不是 i i i,令 y k + 1 = r e s y_{k+1}=res yk+1=res

我们再去假定初始密码是 i + 1 i+1 i+1…反复迭代,显然可以在 n n n次内得到解

#include <bits/stdc++.h>
using namespace std;
const int maxn = 3e5+10; 
int t,n,k;
int guess(int ans)
{
	cout << ans << endl;
	int flag; cin >> flag;
	return flag;
}
signed main()
{
	cin >> t;
	while( t-- )
	{
		cin >> n >> k;
		int res = 0;
		for(int i=0;i<n;i++)
		{
			if( guess(res^i) )	break;
			res ^= ( res^i );	
		}
	}
}

h a r d hard hard

k k k可能不是二进制了.

再看看密码生成的机制(时刻记住这里的异或是对应位相加再模 k k k)

x ⊕ z = y x\\oplus z=y xz=y

我们把 x , y , z x,y,z x,y,z每一位都拆开了,设 z i z_i zi表示 k k k进制下低位起的第 i i i位上的数字

那么 z i = ( ( y i − x i ) % k + k ) % k z_i=((y_i-x_i)\\%k+k)\\%k zi=((yixi)%k+k)%k.为了方便

设初始密码为 p w d pwd pwd

考虑如果是第一次询问,询问数字为 f 1 f_1 f1,猜错答案后新密码变为

z 1 = ( f 1 − p w d ) % k z_1=(f_1-pwd)\\%k z1=(f1pwd)%k

考虑如果是第二次询问,询问数字为 f 2 f_2 f2,猜错答案后新密码变为

z 2 = ( f 2 − z 1 ) % k = ( f 2 − f 1 + p w d ) % k z_2=(f_2-z_1)\\%k=(f_2-f_1+pwd)\\%k z2=(f2z1)%k=(f2f1+pwd)%k

同理第三次生成的新密码是

z 2 = ( f 3 − z 2 ) % k = ( f 3 − f 2 + f 1 − p w d ) % k z_2=(f_3-z_2)\\%k=(f_3-f_2+f_1-pwd)\\%k z2=(f3z2)%k=(f3f2+f1pwd)%k

以此类推…

首先我们可以假定 p w d pwd pwd来求 z z z,求 z z z不就照着上面的公式套嘛!!

有两种大同小异的套法

Ⅰ.按照奇偶性给每次猜测的数 f i f_i fi分类,然后看看是加 p w d pwd pwd还是减 p w d pwd pwd

Ⅱ.每次对之前维护的 f f f值取反,然后加上本次猜测的 f f f值,然后判断是加 p w d pwd pwd还是减 p w d pwd pwd

代码用的Ⅰ

#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e7+10; 
const int mx = 30;
int t,n,k;
int zhi[mx][2],lin[mx],base[mx];
vector<int>vec;
void init()
{	
	for(int i=0;i<mx;i++)	lin[i] = zhi[i][0] = zhi[i][1] = 0;
	base[0] = 1;
	for(int i=1;1ll*base[i-1]*k<=maxn;i++)	base[i] = base[i-1]*k;
}
void fenjie(int x)
{
	vec.clear();
	if( x==0 ){ vec.push_back(0); return; }
	while( x!=0 )	vec.push_back( x%k ), x/=k;
}
int upd(int &x,int y){ x = ( (x+y)%k+k )%k; }
int guess(int ans)
{
	cout << ans Codeforces Round #730 div.2 A-E题解

Codeforces Round #730 (Div. 2) A. Exciting Bets(同余)

Codeforces Round #730 (Div. 2) C. Need for Pink Slips(概率,模拟....)

Codeforces Round #730 (Div. 2) D. RPD and Rap Sheet (交互,从easy到hard)

Codeforces Round #436 E. Fire(背包dp+输出路径)

[ACM]Codeforces Round #534 (Div. 2)