CF1543D1D2(构造,位运算)
CF1543D1D2(构造,位运算)
题意
交互。
猜一个数 \(x\) ,最多 \(n\) 次询问,每次如果猜测失败,要将 \(x\) 变成 \(y\) 如果设此次猜测数字为 \(z\) ,则关系表示为 $ x \oplus _k z = y $ 。这里算符表示 \(k\) 进制下的不进位加法。
思路
一开始没仔细看题,看成 $ x \oplus y = z$ 写easy版本时候因为异或的自反性还给过了。于是hard版莫明其妙狂wa。。。
对这个式子,$ x \oplus _k z = y $ 我们先把未知量丢一边,有 $ x = y \ominus _k z$ 这里的 \(\ominus\) 是 \(\oplus\) 的逆。
然后可以写出一个递推式子。
\[\left\{
\begin{aligned}
x_0 = x \\
x_i = num_i \ominus _k x_{i-1}
\end{aligned}
\right.
\]
这种时候如果找到一个通项式,也就写完了。
此时有两种想法。一种是硬递归展下去,一种是考虑构造一个 \(f(i) = num_i\) 使得 $x_i $ 只和 \(x_0\) 和每次询问数字 \(num_i\) 有关。
我们考虑 \(x_1 = num_1 \ominus x\) 。
则 \(x_2 = num_2 \ominus (num_1 \ominus x)\) 。考虑将前项元素 \(num_1\) 消去
令 \(num_2 = num_1 \ominus num_2\) 。代入上式发现 \(x_2 = x \ominus num_2\) 。满足需求
接下来对 \(x_3 = num_3 \ominus (x \ominus num_2)\) 。有类似构造 \(num_3 = num_3 \ominus num_2\) 。
从而我们知道,只要对每一项分奇偶讨论,就可以迭代寻找答案。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<set>
#include<queue>
#include<map>
#include<stack>
#include<string>
#include<random>
#include<iomanip>
#define yes puts("yes");
#define inf 0x3f3f3f3f
#define ll long long
#define linf 0x3f3f3f3f3f3f3f3f
#define ull unsigned long long
// #define endl '\n'
#define int long long
#define rep(i,a,n) for(int i = a;i <= n;i++)
#define per(i,n,a) for(int i = n;i >= a;i--)
using namespace std;
mt19937 mrand(random_device{}());
int rnd(int x) { return mrand() % x;}
typedef pair<int,int> PII;
const int MAXN =10 + 2e5 ,mod=1e9 + 7;
int get(int x,int y,int k) {
int ans = 0,p = 1;
while(x || y) {
int t1 = x % k,t2 = y % k;
x /= k, y /= k;
ans += (t1 - t2 + k) % k * p;
p *= k;
}
return ans;
}
void solve(){
int n,k; cin >> n >> k;
for(int i = 0;i < n;i ++) {
int t;
if(!i) {
cout << i << endl;
cin >> t;
if(t) return;
}else {
if(i & 1) cout << get(i - 1,i,k) << endl;
else cout << get(i,i - 1,k) << endl;
cin >> t;
if(t) return;
}
}
}
signed main()
{
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
int T;cin>>T;
while(T--)
solve();
return 0;
}