JOISC 2016 神经衰弱
考虑弱化版,当写有同样整数的卡片只有 \(1\) 张时如何做。
可以发现性质。
- \(P_{A_i}\) 最大的 \(i\) 在询问 \((i,x)\) 时必然不返回 \(A_i\)。
- \(P_{A_i}\) 第二大的 \(i\) 在询问 \((i,x)\) 时必然只有一种情况返回 \(A_i\)。
- \(P_{A_i}\) 最小的 \(i\) 在询问 \((i,x)\) 时必然返回 \(A_i\)。
考虑打擂台。动态维护 \([1,i]\) 中 \(P_{A_i}\) 最大和第二大的 \(i\),设为 \(a,b\)。当扩展到 \(i\) 时。
-
若 \(i\) 不是 \([1,i]\) 中 \(P_{A_i}\) 最大或第二大,则询问 \((a,i),(b,i)\) 均返回 \(A_i\),可以确定 \(A_i\) 的值。
-
若 \(i\) 是 \([1,i]\) 中 \(P_{A_i}\) 最大或第二大,则必然有 \((a,i),(a,b)\) 均返回 \(A_a\),或者 \((b,i),(a,b)\) 均返回 \(A_b\),可以确定 \(A_a\) 或 \(A_b\) 的值。
这样,没有被确定的值就是当前的最大和第二大值。若卡片有 \(N\) 张,可以在 \(2N\) 次询问内完成。
现在考虑整道题如何做。
发现上述做法唯一的问题在于,当 \(A_a=A_b\) 时,若新进 \(A_i>A_a\),此时 \((a,i),(b,i),(a,b)\) 返回的值均相等,不能确定保留哪两个数。
为了使返回的值不均相等,可以再记录第三大 \(c\)。此时 \(a,b,c\) 中必然有一个数不同。这样在两两询问中必然有回答不同,可以确定保留哪三个数。
卡片有 \(2N\) 张,上述做法在扩展到 \(i\) 时需要询问 \((i,a),(i,b),(i,c)\) 共 \(3\) 次,总询问数为 \(6N\)。
#include<bits/stdc++.h>
#include "Memory2_lib.h"
#define pb emplace_back
#define mp make_pair
#define pob pop_back
using namespace std;
typedef long long ll;
typedef double db;
const ll maxn=1007,ee=1e18;
ll vis[maxn][maxn],cur[4],tmp[4],ans[maxn];
vector<ll> res[maxn];
ll ask(ll x,ll y){
if(vis[x][y]!=-1) return vis[x][y];
return vis[x][y]=vis[y][x]=Flip(x,y);
}
void Solve(int T,int N){
memset(vis,-1,sizeof(vis));
for(int i=0;i<=2;i++) cur[i]=i;
for(int i=3,tar;i<2*N;i++){
cur[3]=i,tar=3;
for(int a=0,flg;a<4;a++){
flg=1;
for(int b=0,c=-1;b<4;b++)if(a!=b){
tmp[++c]=ask(cur[a],cur[b]);
if(c&&tmp[c]!=tmp[c-1]) flg=0;
}
if(flg){tar=a; break;}
}
ans[cur[tar]]=tmp[0];
for(int a=tar+1;a<4;a++) cur[a-1]=cur[a];
}
tmp[0]=ask(cur[0],cur[1]),tmp[1]=ask(cur[1],cur[2]),tmp[2]=ask(cur[0],cur[2]);
if(tmp[0]==tmp[1]) ans[cur[1]]=tmp[0],ans[cur[0]]=ans[cur[2]]=tmp[2];
else if(tmp[0]==tmp[2]) ans[cur[0]]=tmp[0],ans[cur[1]]=ans[cur[2]]=tmp[1];
else ans[cur[2]]=tmp[1],ans[cur[0]]=ans[cur[1]]=tmp[0];
for(int i=0;i<2*N;i++) res[ans[i]].pb(i);
for(int i=0;i<N;i++) Answer(res[i][0],res[i][1],i);
}