JOISC 2016 神经衰弱

考虑弱化版,当写有同样整数的卡片只有 1 张时如何做。

可以发现性质。

  • PAi 最大的 i 在询问 (i,x) 时必然不返回 Ai
  • PAi 第二大的 i 在询问 (i,x) 时必然只有一种情况返回 Ai
  • PAi 最小的 i 在询问 (i,x) 时必然返回 Ai

考虑打擂台。动态维护 [1,i]PAi 最大和第二大的 i,设为 a,b。当扩展到 i 时。

  • i 不是 [1,i]PAi 最大或第二大,则询问 (a,i),(b,i) 均返回 Ai,可以确定 Ai 的值。

  • i[1,i]PAi 最大或第二大,则必然有 (a,i),(a,b) 均返回 Aa,或者 (b,i),(a,b) 均返回 Ab,可以确定 AaAb 的值。

这样,没有被确定的值就是当前的最大和第二大值。若卡片有 N 张,可以在 2N 次询问内完成。

现在考虑整道题如何做。

发现上述做法唯一的问题在于,当 Aa=Ab 时,若新进 Ai>Aa,此时 (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);
}
posted @   aeiouaoeiu  阅读(5)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示