魔板
- 思想:
相当于在trie树上的KMP。
- 流程:
1.构建trie树
注意0为根会方便很多。
2.get_fail()
虽然和KMP很相似,我举一反三的能力有限,所以还是要重新讲qwq
fail[i]:表示满足i为结尾的后缀与rt开始的前缀匹配的最大长度。
求法为了无后效性,用BFS(按层遍历),每次枚举相邻的trie树继续匹配下去,匹配不明显,但是很短,巧妙地运用了fail和trie的性质。
3.文本串在trie树上浪
从跟开始,记录u指针,逐步往下,每跳一步,不能局限于当前的格局,还要一直迭代到fail=0为止,当然原指针为止不变。
你会发现如果u走不下去了,就会自动为0,到根节点【1明白了吧】,重新匹配。
当然不用想这么多,AC制动机是个DFN,只要暴力往下走就行了。
- 代码:
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+5;
int go[N][27],fail[N],cnt[N],tcnt=0;
char s[N];
void Insert() {
int sz=strlen(s),u=0;
for(int i=0;i<sz;i++) {
int x=s[i]-'a';
if(!go[u][x]) go[u][x]=++tcnt;
u=go[u][x];
}
cnt[u]=1;
}
void get_fail() {
queue<int> Q;
for(int i=0;i<26;i++) if(go[0][i])fail[go[0][i]]=0,Q.push(go[0][i]);
while(!Q.empty()) {
int u=Q.front(); Q.pop();
for(int i=0;i<26;i++) {
if(go[u][i]) fail[go[u][i]]=go[fail[u]][i],Q.push(go[u][i]);
else go[u][i]=go[fail[u]][i];
}
}
}
int Query() {
int sz=strlen(s),u=0,ans=0;
for(int i=0;i<sz;i++) {
u=go[u][s[i]-'a'];
for(int j=u;j&&cnt[j]!=-1;j=fail[j]) {
ans+=cnt[j],cnt[j]=-1;
}
}
return ans;
}
int main() {
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++) {
scanf("%s",s);
Insert();
}
get_fail();
scanf("%s",s);
printf("%d",Query());
return 0;
}
Video Game Combos
- 题意:给了您很多串,您要构造一个K位的文本串,求包含串数的最大值。
- 思路:fail+dp(trie树上的)
首先我们fail利用它“后缀=前缀”的性质,预处理出cnti
cnt[i]=(本身trie预处理时有无串)
cnt[i]+=cnt[fail[i]](显然)
状态:dp[i][j]是:按i下第i下为trie树上的j的得分
dp[i+1][trie[j][i]]=dp[i][j]+cnt[j]
- 代码:
#include<stdio.h>
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+5;
char s[N];
int go[N][5],tcnt,cnt[N],fail[N],dp[3005][3005];
void Insert() {
int sz=strlen(s),u=0;
for(int i=0;i<sz;i++) {
int x=s[i]-'A';
if(!go[u][x]) go[u][x]=++tcnt;
u=go[u][x];
}
cnt[u]++;
}
void get_fail() {
queue<int> Q;
int u=0;
for(int i=0;i<3;i++) if(go[0][i]) Q.push(go[0][i]);
while(!Q.empty()) {
int u=Q.front(); Q.pop();
cnt[u]+=cnt[fail[u]];
for(int i=0;i<3;i++) {
if(go[u][i]) fail[go[u][i]]=go[fail[u]][i],Q.push(go[u][i]);
else go[u][i]=go[fail[u]][i];
}
}
}
int main() {
int n,k,sz=0;
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++) {
scanf("%s",s);
Insert();
sz+=strlen(s);
}
get_fail();
memset(dp,-0x3f,sizeof(dp));
dp[0][0]=0;
for(int i=0;i<k;i++) {
for(int j=0;j<=tcnt;j++) {
for(int x=0;x<3;x++) {
if(go[j][x]) {
int y=go[j][x];
dp[i+1][y]=max(dp[i+1][y],dp[i][j]+cnt[y]);
}
}
}
}
int ans=0;
for(int j=0;j<=tcnt;j++) {
ans=max(ans,dp[k][j]);
}
printf("%d",ans);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· winform 绘制太阳,地球,月球 运作规律
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人