枚举每一个连续的K的第一个位置,如果是先手胜利,那么前[1 , i-1 ]和[ i+k , n ]区间要么全是0,要么全是1
如果能够平局,那么肯定是[1,i-1],以及[ i+k , n]中有两种情况
有一个区间全为0,并且另外有个区间内部最左边的1和最右边的1距离是大于K
有一个区间全为1,并且另外有一个区间内部最左边的0和最右边的0的距离是大于K
或者两个区间均有1或者均有0
如何后手胜利,那么肯定没有平局出现,也就意味着
有一个区间全为0,并且另外有个区间内部最左边的1和最右边的1距离是大于K
有一个区间全为1,并且另外有一个区间内部最左边的0和最右边的0的距离是大于K
由于不带修改,我们可以很简单维护i位置
左边第一次出现1的位置,左边第一次出现0的位置
右边第一次出现1的位置,右边第一次出现0的位置
然后o(n)判断即可,这也算是比较优秀的做法了吧。。。
#include<iostream> #include<string.h> #include<algorithm> #include<stdio.h> using namespace std; const int maxx = 2e5+6; int l1[maxx]; int l0[maxx]; int r1[maxx]; int r0[maxx]; char s[maxx]; int main(){ int n,k; while(~scanf("%d%d",&n,&k)){ scanf("%s",s+1); for (int i=1;i<=n;i++){ if (s[i]=='1'){ l1[i]=i; l0[i]=l0[i-1]; }else { l0[i]=i; l1[i]=l1[i-1]; } } r0[n+1]=n+1; r1[n+1]=n+1; for (int i=n;i>=1;i--){ if (s[i]=='1'){ r1[i]=i; r0[i]=r0[i+1]; }else { r0[i]=i; r1[i]=r1[i+1]; } } int flag=5; for (int i=1;i<=n-k+1;i++){ int ll=1; int lr=i-1; int rl=i+k; int rr=n; if(l1[i-1]==0 && r1[i+k]==n+1){ flag=min(flag,1); } if(l0[i-1]==0 && r0[i+k]==n+1){ flag=min(flag,1); } if (l1[i-1]==0 && l0[n]-r0[i+k]+1<=k){ flag=min(flag,3); } if (l0[i-1]==0 && l1[n]-r1[i+k]+1<=k){ flag=min(flag,3); } if (r0[n+k]==0 && l1[i-1]-r1[1]+1<=k){ flag=min(flag,3); } if (r1[n+k]==0 && l0[i-1]-r0[1]+1<=k){ flag=min(flag,3); } if (r1[n+k]==0 && l0[i-1]-r0[1]+1>k){ flag=min(flag,2); } if (r0[n+k]==0 && l1[i-1]-r1[1]+1>k){ flag=min(flag,2); } if (l1[i-1]==0 && l0[n]-r0[i+k]+1>k){ flag=min(flag,2); } if (l0[i-1]==0 && l1[n]-r1[i+k]+1>k){ flag=min(flag,2); } if (l1[i-1]!=0 && r1[i+k]!=n+1){ flag=min(flag,2); } if (l0[i-1]!=0 && r0[i+k]!=n+1){ flag=min(flag,2); } } if (flag==1){ printf("tokitsukaze\n"); }else if (flag==2){ printf("once again\n"); }else { printf("quailty\n"); } } return 0; }