CodeForces Round #730 D1. RPD and Rap Sheet (Easy Version)题解

12 篇文章 0 订阅

Codeforces Round #730 (Div. 2)

题意:

t组数据,每组给一个n和k,(easy version里面k=2) 每一次系统会输入一个初始的密码(初始密码是一个在 [ 0 , n − 1 ] [0,n-1] [0,n1]的随机值),你可以最多输出n次询问,如果猜对了密码系统会输入1,否则输入0.但密码不是不变的,每次会根据如下公式变化
旧 密 码 ⨁ 新 密 码 = 询 问 值 旧密码\bigoplus新密码=询问值 =

题解:

设初始密码为X,第i次询问值为 P i P_i Pi,新密码为Y

根据异或的交换律得到
旧 密 码 ⨁ 新 密 码 = 询 问 值 → 旧 密 码 ⨁ 询 问 值 = 新 密 码 → X ⨁ P i = Y 旧密码\bigoplus新密码=询问值\to 旧密码\bigoplus询问值=新密码\to X\bigoplus P_i=Y ==XPi=Y
根据异或的结合律
( ( ( X ⨁ P 1 ) ⨁ P 2 ) ⨁ . . . P i ) = X ⨁ ( P 1 ⨁ P 2 ⨁ . . . P i ) (((X\bigoplus P_1) \bigoplus P_2 )\bigoplus ... P_i)=X\bigoplus (P_1 \bigoplus P_2 \bigoplus ... P_i) (((XP1)P2)...Pi)=X(P1P2...Pi)
所以可以把初始密码每次异或一个询问值得到一个新密码简化为是在异或了一堆询问值后得到一个新密码.

现在我们假设 P i = ( i − 1 ) ⨁ P 1 ⨁ P 2 ⨁ . . . P i − 1 P_i=(i-1)\bigoplus P_1 \bigoplus P_2 \bigoplus ... P_{i-1} Pi=(i1)P1P2...Pi1

可以得到
P X + 1 = X ⨁ ( P 1 ⨁ P 2 ⨁ . . . P i ⨁ . . . P X ) P_{X+1}=X\bigoplus (P_1 \bigoplus P_2 \bigoplus ... P_i\bigoplus... P_{X}) PX+1=X(P1P2...Pi...PX)
我们惊奇的发现初始密码X异或上前X个询问的值就是
X ⨁ ( P 1 ⨁ P 2 ⨁ . . . P i ⨁ . . . P X ) X\bigoplus (P_1 \bigoplus P_2 \bigoplus ... P_i\bigoplus... P_{X}) X(P1P2...Pi...PX)
所以询问到第X+1次时其询问值一定等于当前密码的值

还可以想到另一种
P 1 = 0 P i = ( i − 1 ) ⨁ ( i − 2 )   2 < = i < = n P_1=0\\P_i=(i-1)\bigoplus(i-2) \ 2<=i<=n P1=0Pi=(i1)(i2) 2<=i<=n
因为
第 X + 1 次 询 问 : P X + 1 = X ⨁ ( X − 1 ) 而 初 始 密 码 在 经 过 X 次 询 问 等 于 X ⨁ ( 0 ⨁ 1 ⨁ 2 ⨁ 1 ⨁ 3 ⨁ 2 ⨁ . . . X − 1 ⨁ X − 2 ) → X ⨁ ( X − 1 ) 第X+1次询问:P_{X+1}=X\bigoplus(X-1)\\ 而初始密码在经过X次询问等于X\bigoplus(0\bigoplus1\bigoplus 2\bigoplus1\bigoplus3\bigoplus2\bigoplus...X-1\bigoplus X-2)\to X\bigoplus(X-1) X+1:PX+1=X(X1)XX(012132...X1X2)X(X1)
所以询问到第X+1次也可以得到当前密码值

代码:

#include<iostream>
#include<cmath>
#pragma GCC optimize(2)
using namespace std;
typedef long long ll;
const ll mod = 1e9 + 7;
inline ll read();
int main() {
    int t = 1;
    cin >> t;
    while (t--) {
        int n, k;
        cin >> n >> k;
        for (int i = 1; i <= n; i++) {
            if (i == 1)cout << 0 << '\n';
            else{
                cout<<((i-1)^(i-2))<<'\n';
            }
            int res;
            cin >> res;
            if (res == 1)
                break;
        }
    }
    return 0;
}


inline ll read() {
    char ch = getchar();
    ll p = 1, data = 0;
    while (ch < '0' || ch > '9') {
        if (ch == '-')p = -1;
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9') {
        data = data * 10 + (ch ^ 48);
        ch = getchar();
    }
    return p * data;
}
  • 5
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值