题解 CF1762D【GCD Queries】
problem
交互题,评测机有一个排列 \(p:[int]\),值域是 \([0,n)\),现在可以询问 \(2n\) 次 \((x,y)\),评测机回答 \(\gcd(p_x,p_y)\),你需要回答 \(p\) 中 \(0\) 的两个可能的位置。
\(\gcd(x,0)=x\),\(1\leq n\leq 10^4\)。
solution with \(4n\) queries
考虑固定死一个数,就 \(p_1\) 吧,询问它和其它所有数的 \(\gcd\)。将这些 \(\gcd\) 的 \(\operatorname{lcm}\) 拎出来,就是 \(p_1\)。
然后将所有 \(\gcd(p_1,p_i)=p_1\) 的数拎出来(包括 \(0\)),全部除以 \(p_1\),开始递归。
复杂度分析:如果 \(p_1>1\) 那我们很开心得到一个询问 \(2n\) 次的算法(每次至少折半),但是如果 \(p_1=1\)…………
\[\huge{\text{寄}}
\]
而且这样子,我们甚至可以唯一确定 \(0\) 的位置,不太好。
solution with \(2n\) queries
随机三个数 \(i,j,k\),询问 \(x=\gcd(p_i,p_j),y=\gcd(p_i,p_k)\),如果
- \(x=y\),那么 \(p_i\neq 0\)。
- \(x>y\),那么 \(p_k\neq 0\)(考虑当 \(p_k=0\) 时,\(\gcd(p_i,p_j)>p_i\),这也太离谱了,一个数的约数不能大于他)。
- \(x<y\),那么 \(p_j\neq 0\)。
每次用两次询问排除一个数,询问次数自然是 \(2n\)。
code
https://codeforces.com/contest/1762/submission/204571436
// LUOGU_RID: 109661417
#include <queue>
#include <numeric>
#include <cstdio>
#include <vector>
#include <cstring>
#include <algorithm>
using namespace std;
#ifdef LOCAL
#define debug(...) fprintf(stderr,##__VA_ARGS__)
#else
#define debug(...) void(0)
#endif
typedef long long LL;
int n;
int query(int x,int y){
return printf("? %d %d\n",x+1,y+1),fflush(stdout),scanf("%d",&x),x;
}
void report(int x,int y){
printf("! %d %d\n",x+1,y+1),fflush(stdout),scanf("%*d");
}
int mian(){
vector<int> a(n);
iota(a.begin(),a.end(),0);
while(a.size()>=3){
int x=a.back(); a.pop_back();
int y=a.back(); a.pop_back();
int z=a.back(); a.pop_back();
int q1=query(x,y),q2=query(x,z);
if(q1==q2) a.push_back(y),a.push_back(z);
else if(q1>q2) a.push_back(x),a.push_back(y);
else a.push_back(x),a.push_back(z);
}
report(a[0],a[1]);
return 0;
}
int main(){
for(scanf("%*d");~scanf("%d",&n);mian());
return 0;
}
本文来自博客园,作者:caijianhong,转载请注明原文链接:https://www.cnblogs.com/caijianhong/p/solution-cf1762d.html