题目链接:点击查看
题目大意:交互题猜密码,设原密码为 x x x,猜的密码为 y y y,如果没猜到,密码会自适应变成 z z z,满足 x ⊕ z = y x \oplus z=y x⊕z=y ,最多猜 n n n 次,对于本题而言,所有数字是在 k k k 进制下进行的
题目分析:相对于 e a s y easy easy 版本而言,当异或推广到 k k k 进制时,就不存在自反性了,所以本题还是要稍微推一下公式找找共性
这里的异或就不能称之为异或了,下文中, ⊕ \oplus ⊕ 将视为 “k进制不进位加法”,同样对应一个 ⊖ \ominus ⊖ 为 “k进制不退位减法”,意义为名称所述。本题中的异或其实就是“k进制不进位加法”,需要提前知道的是,这两个运算同样具有基本运算的交换律和结合律的性质。
开始推公式,假设原答案为 x x x,猜的密码为 y y y,新密码为 z z z,因为满足 x ⊕ z = y x \oplus z=y x⊕z=y,两侧同时“不进位减去x”,得到 z = y ⊖ x z=y \ominus x z=y⊖x
假设第 i i i 次询问的值为 q i q_i qi,密码为 p a s s w o r d password password,第一次询问后,原密码变成了 q 1 ⊖ p a s s w o r d q_1 \ominus password q1⊖password;第 k k k 次询问后,原密码变成了 q k ⊖ ( q k − 1 ⊖ . . . ( q 2 ⊖ ( q 1 ⊖ p a s s w o r d ) ) ) q_k \ominus(q_{k-1}\ominus...(q_2 \ominus (q_1 \ominus password))) qk⊖(qk−1⊖...(q2⊖(q1⊖password))),这里还是令 q 1 = 0 q_1=0 q1=0
所以假如我们第 i i i 次猜,想要猜原密码是否和 x x x 相等,也就是 p a s s w o r d = = x password==x password==x 是否成立,就必须令 q i = q i − 1 ⊖ ( q i − 2 ⊖ . . . ( q 2 ⊖ ( q 1 ⊖ x ) ) ) q_i=q_{i-1} \ominus(q_{i-2}\ominus...(q_2 \ominus (q_1 \ominus x))) qi=qi−1⊖(qi−2⊖...(q2⊖(q1⊖x)))
现在问题是如何快速求出 q i q_i qi。根据结合律,不难将 x x x 单独拿出来,然后整个式子就变成了: q i = q i − 1 ⊖ ( q i − 2 ⊖ . . . ( q 2 ⊖ q 1 ) ) o p x q_i=q_{i-1} \ominus(q_{i-2}\ominus...(q_2 \ominus q_1))\ \ op\ \ x qi=qi−1⊖(qi−2⊖...(q2⊖q1)) op x,这里的 o p op op 代表的是一个符号,这里先按下不表。不难看出 o p op op 前面的部分可以线性维护得到。而后面单独拆出来的 x x x,因为遇到减法拆括号时需要变号,“不进位减法” 在这里也是同理,所以当询问的下标为奇数时, o p op op 为 ⊖ \ominus ⊖,当询问的下标为偶数时, o p op op 为 ⊕ \oplus ⊕
然后自己模拟一下 ⊕ \oplus ⊕ 和 ⊖ \ominus ⊖ 这两个运算就可以了,按照上面的理论,将 n n n 个数字都枚举一遍, 时间复杂度是 O ( n l o g k n ) O(nlog_kn) O(nlogkn) 的
代码:
// Problem: D2. RPD and Rap Sheet (Hard Version)
// Contest: Codeforces - Codeforces Round #730 (Div. 2)
// URL: https://codeforces.com/contest/1543/problem/D2
// Memory Limit: 256 MB
// Time Limit: 5000 ms
//
// Powered by CP Editor (https://cpeditor.org)
// #pragma GCC optimize(2)
// #pragma GCC optimize("Ofast","inline","-ffast-math")
// #pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<cassert>
#include<bitset>
#define lowbit(x) x&-x
using namespace std;
typedef long long LL;
typedef unsigned long long ull;
template<typename T>
inline void read(T &x)
{
T f=1;x=0;
char ch=getchar();
while(0==isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(0!=isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
x*=f;
}
template<typename T>
inline void write(T x)
{
if(x<0){x=~(x-1);putchar('-');}
if(x>9)write(x/10);
putchar(x%10+'0');
}
const int inf=0x3f3f3f3f;
const int N=1e6+100;
int k;
int add(int a,int b) {
int ans=0,base=1;
while(a||b) {
int tmp=(a%k+b%k)%k;
ans+=tmp*base;
base*=k;
a/=k,b/=k;
}
return ans;
}
int sub(int a,int b) {
int ans=0,base=1;
while(a||b) {
int tmp=(a%k-b%k+k)%k;
ans+=tmp*base;
base*=k;
a/=k,b/=k;
}
return ans;
}
int main()
{
#ifndef ONLINE_JUDGE
// freopen("data.in.txt","r",stdin);
// freopen("data.out.txt","w",stdout);
#endif
// ios::sync_with_stdio(false);
int w;
cin>>w;
while(w--) {
int n,sum=0;
read(n),read(k);
for(int i=0;i<n;i++) {
int cur=1;
if(i==0) {
cur=0;
} else if(i&1) {
cur=sub(sum,i);
} else {
cur=add(sum,i);
}
printf("%d\n",cur);
fflush(stdout);
int ans;
scanf("%d",&ans);
if(ans==1) {
break;
} else {
sum=sub(cur,sum);
}
}
}
return 0;
}