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)相关的知识,希望对你有一定的参考价值。
题意
已知密码是 k k k进制数,在十进制下是 [ 0 , n − 1 ] [0,n-1] [0,n−1]之间,你有至多 n n n次机会猜测这个数
设你猜的数字是 y y y,如果答案正确,系统会返回 1 1 1
如果答案错误,系统将返回 0 0 0,而且会修改密码为 z z z
x ⊕ z = y x\\oplus z=y x⊕z=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=x⊕y
考虑枚举每个数为初始密码
比如我认为 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=y1⊕y2...⊕yk⊕i
于是我们猜测当前密码是 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 x⊕z=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=((yi−xi)%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=(f1−pwd)%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=(f2−z1)%k=(f2−f1+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=(f3−z2)%k=(f3−f2+f1−pwd)%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)