JOISC 2016 神經衰弱

aeiouaoeiu發表於2024-11-08

考慮弱化版,當寫有同樣整數的卡片只有 \(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);
}

相關文章