CF1190C Tokitsukaze and Duel

搬运一下本喵的 lg 博客 qwq

详细讲一下如何判定后手能否获胜,对其他题解做个补充。(蒟蒻的我想了好久来着

此题的关键点在于可以重复上一个人的操作使局面保持不变。

考虑先手的获胜条件,由上一段可知若先手不能在第一步获胜,则后手一定可以重复先手的操作,使其回到原来的局面,从而保证自己不败。

考虑后手的获胜条件,与先手同理,若后手不能一步致胜,先手同样可以重复后手的操作。

综上所述,当且仅当其中一人能够一步致胜时,才能获得胜利


先手

若先手一步致胜,则需保证所选区间以外的数字全部相同

对于串中的位置 \(i\) ,维护 \(l_i\)\(r_i\) 分别表示其左边及右边在字符相同时的最远位置。

枚举所选长度为 \(k\) 的区间为 \([i,j]\),当 \(l_i=1\)\(r_j=n\)\(a_{i-1}=a_{j+1}\) 时,满足区间外的所有数字相同,可以获胜。

后手

后手获胜,需要保证先手做出任何选择都能使后手一步致胜

设先手选择的区间为 \([i,j]\) 。把当前局面分成三部分,分别为 \([1,i-1]\)\([i,j]\)\([j+1,n]\) 。后手想要获胜,必须使左右两区间的所有值都与 \([i,j]\) 的值相等。而在一次操作中,后手只能操作其中的一个区间。也就是说,需要保证其中的一个区间值全部与 \([i,j]\) 相等。

\(n>2k\) 时, \([1,i-1]\)\([j+1,n]\) 必然有一个长度大于 \(k\)。此时后手无法获胜。

这时候我们会发现一个问题,假设 \([1,i-1]\) 的值全为 \(0\) ,且 \([j+1,n]\) 中不全是同一个值,那么先手只要把 \([i,j]\) 全部变为 \(1\) ,后手还是无法胜利。因此要保证无论先手填的值是什么,都有其中一个区间与之全部相等,就需要左右两个区间一个全是 \(0\),一个全是 \(1\)

因此,若存在 \([i,j]\) 不满足 \(l_{i - 1} = 1\)\(r_{j+1} = n\) ,后手无法获胜。

\(code:\)

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int n,k,a[N];
int l[N],r[N];
char s[N];
int main()
{
	scanf("%d%d%s",&n,&k,s+1);
	for(int i=1;i<=n;i++)
	{
		if(s[i]=='0') a[i]=0;
		else a[i]=1;
	}
	l[1]=1;l[0]=1;
	for(int i=2;i<=n;i++)
	{
		if(a[i]==a[i-1]) l[i]=l[i-1];
		else l[i]=i;
	}
	r[n]=n;r[n+1]=n;
	for(int i=n-1;i;i--)
	{
		if(a[i]==a[i+1]) r[i]=r[i+1];
		else r[i]=i;
	}
	for(int i=1;i<=n-k+1;i++)
	{
		int j=i+k-1;
		if(l[i-1]==1&&r[j+1]==n&&a[i-1]==a[j+1])
		{
			cout<<"tokitsukaze"<<endl;
			return 0;
		}
	}
	if(n>2*k)
	{
		cout<<"once again"<<endl;
		return 0;
	}
	bool flag=0;
	for(int i=2;i<=n-k;i++)
	{
		if(l[i-1]!=1||r[i+1]!=n)
		{
			cout<<"quailty"<<endl;
			return 0;
		}
	}
	cout<<"once again"<<endl;
	return 0;
}
			
		
	
posted @ 2022-07-24 14:56  樱雪喵  阅读(30)  评论(0编辑  收藏  举报