题意

给一个字符串\(s\),和\(n\)个子串\(t[i]\),两个人博弈,每次取出一个串\(t[i]\),在后面加入一个字符,保证新字符串仍然是\(s\)的子串,无法操作的人输。

分析

  • n个子串,类比于n堆石子,如果把子串\(t[i]\)在后面加若干字符能生成的子串看出一个状态,用一个数表示,那每次状态的变化,就类比于对一堆石子取走若干个,无法操作,就类比于没有石子可以取。
  • 多堆取石子游戏的做法就是把每堆石子的SG值(sg(x)=x)异或起来,不为零就先手赢,否则后手赢。
  • 所以可以将题目转化为求每个子串\(t[i]\)对应状态的SG值。
  • 然后就是后缀自动机的套路,每个子串就可以对应SAM上的一个节点,所以可以直接dfs记忆化搜索SG值。

代码

#include <bits/stdc++.h>
using namespace std;
const int N=1e5+50;
char s[N];
int n;
struct SAM{
int nex[N*2][26],fa[N*2],len[N*2],num[N*2];
int cnt,lst;
int sg[N*2];
int newnode(int l,int s){
for(int i=0;i<26;i++){
nex[cnt][i]=0;
}
len[cnt]=l;
num[cnt]=s;
return cnt++;
}
void init(){
cnt=0;
lst=newnode(0,0);
fa[lst]=-1;
memset(sg,-1,sizeof(sg));
}
void add(int c){
c-='a';
int p=lst;
int cur=newnode(len[p]+1,1);
while(p!=-1 && !nex[p][c]){
nex[p][c]=cur;
p=fa[p];
}
if(p==-1){
fa[cur]=0;
}else{
int q=nex[p][c];
if(len[q]==len[p]+1){
fa[cur]=q;
}else{
int cl=newnode(len[p]+1,0);
fa[cl]=fa[q];
memcpy(nex[cl],nex[q],sizeof(nex[cl]));
while(p!=-1 && nex[p][c]==q){
nex[p][c]=cl;
p=fa[p];
}
fa[q]=fa[cur]=cl;
}
}
lst=cur;
}
int w[N*2],tp[N*2];
void dfs(int u){
int vis[30]={0};
if(sg[u]!=-1){
return;
}
for(int i=0;i<26;i++){
int v=nex[u][i];
if(v){
dfs(v);
vis[sg[v]]=1;
}
}
for(int i=0;i<26;i++){
if(!vis[i]){
sg[u]=i;
break;
}
}
}
void sfd(int l){
for(int i=0;i<=l;i++){
w[i]=0;
}
for(int i=1;i<=cnt;i++){
w[len[i]]++;
}
for(int i=2;i<=l;i++){
w[i]+=w[i-1];
}
for(int i=cnt-1;i>=1;i--){
tp[w[len[i]]--]=i;
}
sg[lst]=0;
int vis[30]={0};
for(int i=cnt-1;i>=0;i--){
int u=tp[i];
memset(vis,0,sizeof(vis));
for(int j=0;j<26;j++){
int v=nex[u][j];
if(v){
vis[sg[v]]=1;
}
}
for(int j=0;j<26;j++){
if(!vis[j]){
sg[u]=j;
break;
}
}
}
}
int solve(char *s){
int rt=0;
int l=strlen(s);
for(int j=0;j<l;j++){
rt=nex[rt][s[j]-'a'];
}
return sg[rt];
}
}ac;
int main(){
// freopen("in.txt","r",stdin);
while(~scanf("%s",s)){
ac.init();
int len=strlen(s);
for(int i=0;i<len;i++){
ac.add(s[i]);
}
//dfs或者拓扑排序求sg函数
// ac.dfs(0);
ac.sfd(len);
scanf("%d",&n);
int ans=0;
for(int i=1;i<=n;i++){
scanf("%s",s);
ans^=ac.solve(s);
}
if(ans){
printf("Alice\n");
}else{
printf("Bob\n");
}
}
return 0;
}

最新文章

  1. Android 开机自启服务
  2. iOS_Swift初识之使用三种回调方式自定义Button
  3. soap发送报文请求和dom4j解析XML并且获得指定名称的节点信息
  4. jquery简单原则器(匹配偶数元素)
  5. java大数取模
  6. 关于 jsonp 跨域
  7. 基于K2 BPM的大型连锁企业开关店选址管理解决方案
  8. IOS基础框架
  9. ACM、OI等比赛中的程序对拍问题
  10. POJ 1328 Radar Installation#贪心(坐标几何题)
  11. Java基础系列--集合之ArrayList
  12. Python内置函数(55)——round
  13. EXCEL公式及宏
  14. 【vue】vue +element 搭建项目,将js函数变成vue的函数
  15. FormatMessage
  16. Windows 7 下如何配置 java 环境变量
  17. LOJ-10102(求A到B之间的割点)
  18. Hadoop HBase概念学习系列之HBase里的客户端和HBase集群建立连接(详细)(十四)
  19. CentOS下查看最后登录的用户信息以及LOG记录
  20. hihocoder1415 后缀数组三&#183;重复旋律3

热门文章

  1. 微信小程序获取手机号码看这篇文章就够了
  2. Codeforces 938D Buy a Ticket
  3. codeforces 454 D. Little Pony and Harmony Chest(状压dp)
  4. hdu1255 覆盖的面积(线段树面积交)
  5. 章节十六、7-DataProviders
  6. 基于SSM的在线考试系统
  7. Django之FBV和CBV的用法
  8. 使用Python SMTP发送邮件
  9. [大数据学习研究]1.在Mac上利用VirtualBox搭建本地虚拟机环境
  10. .net core 自定义404 500页面