Codeforces 1375F - Integer Game(交互)

Codeforces 题面传送门 & 洛谷题面传送门

一个奇怪的做法。

首先我们猜测答案总是 First。考虑什么样的情况能够一步把对方一步干掉。方便起见我们假设 \(a<b<c\),那么如果 \(b-a=c-b\),并且上一步后手选择操作 \(c\),那么我们只需令 \(y=b-a\),不论后手再选择了哪一堆,总会出现两个石子数相同的堆,后手也就挂了。我们考虑怎样将所有情况归约到这种情况,经过仔细(反正这一步我是想了 ~1h)的思考,我发现对于 \(a,b,c\) 成等差数列,且上一步选择的是 \(a\) 对应的堆的情况也能把对方干掉,具体构造就是

\(d=b-a\),然后

  • 第一步,选择 \(y=d\),那么此时后手只能选 \(c\)​ 对应的堆,此时三堆分别是 \(a,a+d,a+3d\)
  • 第二步,选择 \(y=5d\),那么如果后手选择第一堆,那么三堆分别是 \(a+5d,a+d,a+3d\),回到了上面一次操作即可挂掉的情况。如果后手选择第二堆,那么三堆分别是 \(a,a+6d,a+3d\),也回到了上面的情况。

我们考虑如何将一般性的情况归约到上面两种情况。我们假设 \(d_1=b-a,d_2=c-b\),那么我们考虑这样一个做法,令 \(y=d_1-d_2\),那么

  • 如果后手选第一堆,就回到了上面等差数列、且一步即可干掉的情况
  • 如果后手选第三堆,就回到了上面等差数列、且两步(第一次 \(y=d\),第二次 \(y=5d\))可以干掉的情况
  • 如果后手选择第二堆,那么我们再次假设 \(d_1’=b-a,d_2’=c-b\),并且假设 \(b+d_1-d_2<c\) 恒成立,那么我们再令 \(y=d’_1-d’_2\),就回到了上面的情况,又因为此时后手显然不能选第二堆,因此不会出现递归,也就证明了构造的正确性。

但是这个做法要能够行得通需要有一些条件,首先你第一次必须有 \(y>0\),因此需有 \(d_1>d_2\),还有就是第二步中我们有 \(b+d_1-d_2<c\) 的假设,即 \(d_1<2d_2\),因此该做法行得通的条件是 \(d_2\le d_1<2d_2\)(至于为什么左边可以取等,是因为 \(d_1=d_2\) 的情况本身就是等差数列,可以归约到上面的第二种情况)。考虑怎样将其他情况转化为这两种情况,每次只需令 \(y=d_1+d_2\) 直到 \(d_2\le d_1<2d_2\) 成立即可。证明大概就,从第一次操作结束以后开始,我们每次操作的元素肯定会成为三个数的最大值对吧,那么从第一轮以后后手只能操作中间那个元素,因此问题可以转化为这样一个问题,有两个数 \(x,y\),每次操作需执行 \(\text{swap}(x,y)\),并令 \(x\leftarrow x+y\),问什么时候 \(y\le x<2y\) 成立,如果 \(x\ge 2y\),那么进行一次操作以后 \(x\le x+y<2x\) 符合条件;如果 \(x<y\),那么换完以后 \(x\leftarrow x+y,y\leftarrow x\),回到了 \(x\ge 2y\) 的情况,因此我们总可以将问题转化为 \(d_2\le d_1<2d_2\) 的情况。

int _1,_2,_3;
pair<ll,int> a[4];int flg=0;
void getid(){sort(a+1,a+4);_1=a[1].se,_2=a[2].se,_3=a[3].se;}
void prt(){
	for(int i=1;i<=3;i++) for(int j=1;j<=3;j++) if(a[j].se==i)
		printf("%d%c",a[j].fi," \n"[i==3]);
	printf("%d %d %d\n",_1,_2,_3);
}
void oper(ll x){
	if(!x) return;
	printf("%lld\n",x);fflush(stdout);
	int p;scanf("%d",&p);
	if(!p) exit(0);
	if(p==_1) a[1].fi+=x,flg=1;
	if(p==_2) a[2].fi+=x,flg=2;
	if(p==_3) a[3].fi+=x,flg=3;
//	prt();
	getid();
}
void work(int stage){
	if(stage==2){
		oper(abs(a[3].fi-a[2].fi));
	} else {
		oper(abs(a[3].fi-a[2].fi));
		oper(5*abs(a[2].fi-a[1].fi));
		work(2);
	}
}
int main(){
	scanf("%lld%lld%lld",&a[1].fi,&a[2].fi,&a[3].fi);puts("First");
	a[1].se=1;a[2].se=2;a[3].se=3;getid();
	if(2ll*a[2].fi==a[1].fi+a[3].fi) work(1);
	else{
		ll d1=abs(a[2].fi-a[1].fi),d2=abs(a[3].fi-a[2].fi);
		while(d2*2<d1||d1<d2){
			oper(d1+d2);d1=abs(a[2].fi-a[1].fi);
			d2=abs(a[3].fi-a[2].fi);
		} //puts("-1");
		oper(abs(d1-d2));
		if(flg==1) work(1);
		else if(flg==2){
			d1=abs(a[2].fi-a[1].fi),d2=abs(a[3].fi-a[2].fi);
			oper(abs(d1-d2));
			if(flg==1) work(1);
			else work(2);
		} else work(2);
	}
	return 0;
}
posted @ 2021-09-16 22:35  tzc_wk  阅读(43)  评论(0)    收藏  举报