[计蒜客][是男人就过 8 题--Pony.AI 题] A String Game

Zarxdy34 posted @ 2018年3月27日 21:48 in 计蒜客 with tags SAM SG函数 , 400 阅读

        题目链接:https://nanti.jisuanke.com/t/24852

        题目大意:给出模板串\(T\)和\(n\)个\(T\)的子串\(S_i\),两个人轮流选择一个子串\(S_i\),在它的后面加一个字符,使得变化后的\(S_i\)仍然为\(T\)的子串,无法操作的人失败,Alice先手Bob后手,两个人都足够聪明,问谁获胜。(\(|T|\leq 10^5\),字符串总长不超过\(3 \cdot 10^7\))

        题解:这个是个典型的nim博弈问题,对模板串建后缀自动机,然后在后缀自动机上算SG函数,每次算\(S_i\)的SG值只要从后缀自动机的root沿着边走到对应位置取它的SG值就好了。最后把每个子串的SG值异或,如果为正则Alice必胜。由于还不是很懂sg函数,先暂时这么放着。

 

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=1e5+10;

struct Suffix_Auto_Maton
{
    struct State
    {
        int next[26],link,len;
    }st[maxn<<1];
 
    int last,cnt;
	int SG[maxn<<1];

	void clear(State *x)
	{
		x->link=x->len=0;
		memset(x->next,0,sizeof(x->next));
	}
	void init() {last=cnt=1;memset(SG,0xFF,sizeof(SG));clear(&st[1]);}
 
    void insert(int c)
    {
        int x=++cnt,p;
		clear(&st[cnt]);
        st[x].len=st[last].len+1;
        for (p=last;p && !st[p].next[c];p=st[p].link) st[p].next[c]=x;
        if (!p) st[x].link=1;
        else {
            int q=st[p].next[c];
            if (st[p].len+1==st[q].len) st[x].link=q;
            else {
                int v=++cnt;
				clear(&st[cnt]);
                st[v].len=st[p].len+1;
                memcpy(st[v].next,st[q].next,sizeof(st[v].next));
                st[v].link=st[q].link;
                for (;p && st[p].next[c]==q;p=st[p].link) st[p].next[c]=v;
                st[q].link=st[x].link=v;
            }
        }
        last=x;
    }

	int Get_SG(int x)
    {
        if (SG[x]>=0) return SG[x];
        int q[26],qnum=0;
        for (int i=0;i<26;i++) if (st[x].next[i]) q[qnum++]=Get_SG(st[x].next[i]);
        sort(q,q+qnum);
        SG[x]=0;
        for (int i=0;i<qnum;i++) if (SG[x]==q[i]) SG[x]++;
        return SG[x];
    }

	int sg(char *s)
	{
		int len=strlen(s);
		int x=1;
		for (int i=0;i<len;i++) x=st[x].next[s[i]-'a'];
		return Get_SG(x);
	}
}S;

char t[maxn],s[maxn];
int n,ans,length;

int main()
{
	while (scanf("%s",t)!=EOF)
	{
		scanf("%d",&n);
		length=strlen(t);
		S.init();
		for (int i=0;i<length;i++)
			S.insert(t[i]-'a');
		ans=0;
		while (n--)
			scanf("%s",s),ans^=S.sg(s);
		printf("%s\n",(ans>0)?"Alice":"Bob");
	}
	return 0;
}

登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter