题目链接
题目大意
有一个长度为n的01串,两个人轮流操作,每次可以选择长度为k的连续子串把他们变成相同的数字,都为1或者都为0,当这个串中所有的字符都是一样的时候结束游戏,两个人都用最优的策略,判断游戏结果
解题思路
这个博弈推的我脑仁疼。。。。。
首先我们知道,先手第一步如果不能赢的话,那他就赢不了了,后手第一步赢不了,那他了赢不了了,因为会进入无休止的扯皮的状态。
那么先手的输赢就很好判断,我们找出0的第一个位置a1和最后一个位置a2,1的第一个位置b1和最后一个位置b2,那么如果(a2-a1)<=k||(b2-b1)<=k或者整个串开始的时候都是一样的,那么先手必胜。
再来讲,如果k*2<n的话,那就一定平手,因为两步无法覆盖整个串,那么就会有无休止的扯皮,无用的反转直到平手为止
那么现在需要判断后手一步能不能赢:后手能赢的必要条件是先手不管怎么搞,后手都能赢。因为 k*2>=n 所以先手一定不会从两端取连续的序列,因为:
比如先手从左边取了连着k个把他们翻成一样的,那么剩下的长度一定是小于等于k的,后手可以一下子把剩下的给反转成一样的。
所以先手一定是从中间选一段使得中间一段是一样的。
例如这个区间是这样的:
那么后手想要一步就要把他们反转成一样的,就要让余下的串和两端是一样的,也就是假如,两端是0和1
那就是要蓝色的区间都和第一元素一样,假设是0,橙色区间的都和最后一个元素一样都是1,这样,不管k这个区间先手把它转为1还是0,都可以和蓝色或者橙色的区间连接上,剩下的区间后手一步就可以翻转成和先手翻转的一样了。
所以我们枚举这个k区间,不管这个区间从哪里开始,都蓝色区间和橙色区间都是分别和首尾元素一样的话,后手就必胜。
剩下的就是平局态了
这个题完结。。。我脑瓜仁疼。。。。。
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int N=1e5+5;
char s[N];
int main()
{
int n,k;
scanf("%d %d",&n,&k);
scanf("%s",s+1);
int a1=0,a2=0,b1=0,b2=0;
for(int i=1;i<=n;i++)
{
if(s[i]=='0'&&a1==0)
a1=i;
if(s[i]=='1'&&b1==0)
b1=i;
}
for(int i=n;i>=1;i--)
{
if(s[i]=='0'&&a2==0)
a2=i;
if(s[i]=='1'&&b2==0)
b2=i;
}
if((a2-a1+1)<=k||(b2-b1+1)<=k||(b1==0&&b2==0)||(a1==0&&a2==0))//先手必胜状态
{
printf("tokitsukaze\n");
return 0;
}
if(k*2<n)
{
printf("once again\n");
return 0;
}
int flag=0;
for(int i=2;i+k<n;i++)//枚举k区间
{
if(s[i]!=s[1])
flag=1;
if(s[n-i+1]!=s[n])
flag=1;
}
if(!flag)
printf("quailty\n");
else
printf("once again\n");
return 0;
}