题解 CF1163D 【Mysterious Code】

土田共戈

2020-04-13 16:08:01

Solution

此题也可以使用 AC 自动机解决 首先可以看出是字典树有关的,显然要在字典树上跑 DP 但是如果加上一个不匹配字符就可能跑到另一个节点,这时就可以想到 AC 自动机 在 AC 自动机上每个节点记录这个节点表示的前缀的后缀是否包含串 s 和串 t,记$f_{i,j}$表示填到第$i$个位置,在字典树上第$j$个节点的最优答案,据此 DP 一下就完了 ```cpp #include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<queue> #define db double #define INF 2147483647 #define LLINF 9223372036854775807 #define LL long long using namespace std; int inline read(){ int num=0,neg=1;char c=getchar(); while(!isdigit(c)){if(c=='-')neg=-1;c=getchar();} while(isdigit(c)){num=(num<<3)+(num<<1)+c-'0';c=getchar();} return num*neg; } const int maxn=1010; int n,l1,l2;char str[maxn],s[maxn],t[maxn]; int ch[maxn][26],fail[maxn],sum[maxn],f[maxn][maxn],cnt; void insert(char *str,int n,int flg){ int now=0; for(int i=1;i<=n;i++){ if(!ch[now][str[i]-'a'])ch[now][str[i]-'a']=++cnt; now=ch[now][str[i]-'a']; }sum[now]+=flg; }queue<int>que;int q[maxn],r; void bfs(){ que.push(0); while(!que.empty()){ int x=que.front();q[++r]=x;que.pop(); if(!x){ for(int i=0;i<26;i++) if(ch[0][i])fail[ch[0][i]]=0,que.push(ch[0][i]);continue; } for(int i=0;i<26;i++) if(ch[x][i]){ fail[ch[x][i]]=ch[fail[x]][i];que.push(ch[x][i]); }else ch[x][i]=ch[fail[x]][i]; }for(int i=2;i<=r;i++)sum[q[i]]+=sum[fail[q[i]]]; } int main() { scanf("%s",str+1);n=strlen(str+1); scanf("%s",s+1);l1=strlen(s+1);insert(s,l1,1); scanf("%s",t+1);l2=strlen(t+1);insert(t,l2,-1);bfs(); for(int i=0;i<=n;i++) for(int j=0;j<=cnt;j++)f[i][j]=-INF/3;f[0][0]=0; for(int i=0;i<n;i++){ for(int j=0;j<=cnt;j++){ if(f[i][j]==-INF/3)continue; for(int k=0;k<26;k++){ if(str[i+1]!=k+'a'&&str[i+1]!='*')continue;int to=ch[j][k]; f[i+1][to]=max(f[i+1][to],f[i][j]+sum[to]); } } }int ans=-INF; for(int i=0;i<=cnt;i++)ans=max(ans,f[n][i]); printf("%d",ans);return 0; } ```