题解:P11818 [PA 2019 Final] 一安在? / Gdzie jest jedynka? 2
这是一个严格小等于 2n 的做法
一个非常显然的结论。
若
证明:因为
我们又发现,
考虑这样一种方法。定义两个指针
-
\gcd(a_l,a_i) > \gcd(a_l,a_r)
把
-
\gcd(a_l,a_i) < \gcd(a_l,a_r)
将
其实这样并不能求出最大的
但是我们发现每次情况
- 若
\gcd(a_l,a_i) = 1 则不执行3 操作。 - 若出现一对
i,j 被ask 过,且其ask 的值>1 则标记i,j ,使其在最后求1 的位置时直接跳过。
正确性显然,同时若
AC code
#include <bits/stdc++.h>
using namespace std;
int ask(int, int);
int solve(int n){
bool f1 = true,ep = false,en[500010];
int cnt = 0;//这个是用来验证正确性的
for(int i = 0;i < n;i++)
en[i] = true;
int l = 0,r = 1,vl = ask(l,r);
cnt++;
if(vl > 1)en[r] = false,f1 = false;
for(int i = 2;i < n;i++){
int vi = ask(l,i);
cnt++;
if(vi == 1)continue;
f1 = false,en[i] = false;
if(vi == vl)l = r,r = i,vl = ask(l,r),cnt++;
else if(vi > vl)r = i,vl = vi;
}
if(cnt >= 2 * n)exit(0);
if(f1)return 0;
int i1 = -1;
for(int i = 1;i < n;i++){
if(!en[i])continue;
if(ep){
int vi = ask(r,i);
cnt++;
if(cnt >= 2 * n)exit(0);
if(vi == 1)return i;
}
else {
int vi = ask(l,i);
cnt++;
if(cnt > 2 * n)exit(0);
if(vi != 1)continue;
if(i1 == -1)i1 = i;
else {
ep = true;
int ax = ask(r,i1);
cnt++;
if(cnt >= 2 * n)exit(0);
if(ax == 1)return i1;
ax = ask(r,i);
cnt++;
if(cnt >= 2 * n)exit(0);
if(ax == 1)return i;
}
}
}
if(cnt >= 2 * n)exit(0);
return i1;
}