1 条题解
-
0
自动搬运
来自洛谷,原作者为

¶凉笙
Inner Peace搬运于
2025-08-24 21:45:07,当前版本为作者最后更新于2021-07-18 11:15:53,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
[题解] [USACO13MAR]Necklace G
前置知识
- AC 自动机。
如果你不会,可以看看 这篇文章(我不会告诉你我是来推销博客的。
请确保您已经学会 AC 自动机。
解题报告
对于题中的两个字符串,显然奶牛的名字是模式串,我们先把它插入到 AC 自动机中。
没有什么正确的贪心做法,因此考虑 DP。
设题目中项链的字符串为 ,奶牛的名字为 , 表示已经考虑了 的前 个字符,在 AC 自动机上对应的第 个结点的最大保留长度。
-
设 为上一个结点 的 指针,如果指向的不是 结束的位置,那么 。
-
同样地,如果当前位置不是 的结束位置,那么 。
最后答案取个 max,用总长度减去就好了。
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; template <typename T> inline T read(){ T x=0;char ch=getchar();bool fl=false; while(!isdigit(ch)){if(ch=='-')fl=true;ch=getchar();} while(isdigit(ch)){ x=(x<<3)+(x<<1)+(ch^48);ch=getchar(); } return fl?-x:x; } #include <queue> const int maxn = 1000 + 10; int f[maxn*10][maxn]; namespace AC{ int t[maxn][26],fail[maxn],end[maxn],cnt=0; void insert(char *s){ int u=0; for(int i=1;s[i];i++){ if(!t[u][s[i]-'a'])t[u][s[i]-'a']=++cnt; u=t[u][s[i]-'a']; } end[u]=1; } queue<int> q; void build(){ for(int i=0;i<26;i++)if(t[0][i])q.push(t[0][i]); while(q.size()){ int u=q.front();q.pop(); for(int i=0;i<26;i++){ if(t[u][i])fail[t[u][i]]=t[fail[u]][i],q.push(t[u][i]); else t[u][i]=t[fail[u]][i]; } } } } using namespace AC; char s[maxn],T[maxn*10]; int main(){ cin>>T+1>>s+1; insert(s);build(); int len=strlen(T+1); for(int i=1;i<=len;i++){ for(int j=0;j<=cnt;j++){ if(!end[t[j][T[i]-'a']]) f[i][t[j][T[i]-'a']]=max(f[i][t[j][T[i]-'a']],f[i-1][j]+1); if(!end[j]) f[i][j]=max(f[i][j],f[i-1][j]); } } int ans=0; for(int i=0;i<=cnt;i++)ans=max(ans,f[len][i]); printf("%d\n",len-ans); return 0; }
小结
个人认为 AC 自动机只是简化了 DP 的过程,并且便于理解。
本质上和其它题解的线性 DP 还是一样的。
- 1
信息
- ID
- 2146
- 时间
- 1000ms
- 内存
- 128MiB
- 难度
- 5
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者