CF305E Playing with String

难点在于读题发现 \(l\) 总取 \(1\) 即可,然后稍加转换就变成个傻逼题了

有个显而易见的 \(O(n^3)\) 的区间 DP 做法,即考虑记录每个区间的 SG 函数值,然后枚举分界点转移

但仔细思考我们会发现能进行操作的只有初始时 \(s_{i-1}=s_{i+1}\) 的位置,并不会经过某些操作后使得一个本来不能操作的位置变得可以操作了

因此我们只需要考虑所有初始时 \(s_{i-1}=s_{i+1}\) 的位置,不妨称这些位置为关键位

手玩下会发现不相邻的两个关键位之间是完全独立的,不会相互影响;反之相邻的关键位会因为其中某个位置操作后导致相邻的位置不能操作

因此我们只关心相连的一段关键位的长度,令 \(f_x\) 表示长为 \(x\) 的关键位对应的 SG 函数,转移暴力枚举所有后继状态即可

总复杂度 \(O(n^2)\)

#include<cstdio>
#include<iostream>
#include<cstring>
#define RI register int
#define CI const int&
using namespace std;
const int N=5005;
int n,sg[N],vis[N],key[N],L[N],R[N]; char s[N];
int main()
{
    scanf("%s",s+1); n=strlen(s+1);
    for (RI i=1;i<=n;++i)
    {
        memset(vis,0,sizeof(vis));
        for (RI j=1;j<=i;++j)
        {
            int x=max(0,j-2),y=max(0,i-j-1);
            vis[sg[x]^sg[y]]=1;
        }
        int mex=0; while (vis[mex]) ++mex;
        sg[i]=mex;
    }
    for (RI i=2;i<n;++i) if (s[i-1]==s[i+1]) key[i]=1;
    int ret=0; for (RI i=1,j;i<=n;)
    {
        if (!key[i]) { ++i; continue; }
        for (j=i;j<=n&&key[j];++j);
        ret^=sg[j-i]; i=j;
    }
    if (ret==0) return puts("Second"),0;
    for (RI i=1;i<=n;++i) if (key[i-1]) L[i]=L[i-1]+1; else L[i]=0;
    for (RI i=n;i>=1;--i) if (key[i+1]) R[i]=R[i+1]+1; else R[i]=0;
    puts("First");
    for (RI i=1;i<=n;++i) if (key[i])
    {
        int x=max(0,L[i]-1),y=max(0,R[i]-1);
        if ((ret^sg[L[i]+R[i]+1]^sg[x]^sg[y])==0) return printf("%d",i),0;
    }
    return 0;
}
posted @ 2024-08-07 18:44  空気力学の詩  阅读(19)  评论(0编辑  收藏  举报