HDU - 6583 Typewriter (后缀自动机+dp)
题意:你要打印一段字符串,往尾部添加一个字符需要花费p元,复制一段字符到尾部需要花费q元,求打印完全部字符的最小花费。
一开始想的贪心,后来发现忘了考虑p<q的情况了,还纳闷怎么不对..(囧)
设为打印完前i个字符的最小花费
第一种转移是,可以直接转移
第二种转移是,对于每个i需要找到最大的j,使得是的子串。说到子串,就自然能想到后缀自动机。我们可以在i右移的同时扩展当前的后缀自动机,然后让j也右移,直到不能转移为止。如果对于每个i都让j从i开始往后走的话复杂度是的,会T掉,因此需要改进一下。有一个很巧妙的做法,用尺取的方法,每当i右移的时候,不必让j再从i开始走一遍,而是直接右移,如果不能转移的话,就尝试往父结点走,直到有转移为止,注意mxl(结点子串最大长度)不得小于j-i,否则无法完全覆盖区间。这样复杂度就是了。
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int N=4e5+10,M=26; 5 char s[N]; 6 int n,fa[N],go[N][M],mxl[N],last,tot,p,q; 7 ll dp[N]; 8 int newnode(int l) {int u=++tot; mxl[u]=l,memset(go[u],0,sizeof go[u]); return u;} 9 void add(int ch) { 10 int p=last,np=last=newnode(mxl[p]+1); 11 for(; p&&!go[p][ch]; p=fa[p])go[p][ch]=np; 12 if(!p)fa[np]=1; 13 else { 14 int q=go[p][ch]; 15 if(mxl[q]==mxl[p]+1)fa[np]=q; 16 else { 17 int nq=newnode(mxl[p]+1); 18 memcpy(go[nq],go[q],sizeof go[q]); 19 fa[nq]=fa[q],fa[q]=fa[np]=nq; 20 for(; p&&go[p][ch]==q; p=fa[p])go[p][ch]=nq; 21 } 22 } 23 } 24 int main() { 25 while(scanf("%s%d%d",s,&p,&q)==3) { 26 n=strlen(s),tot=0; 27 last=newnode(0); 28 memset(dp,0x3f,sizeof dp),dp[0]=0; 29 for(int i=0,j=0,u=1; i<n; add(s[i]-'a'),++i) { 30 for(; j<n; u=go[u][s[j]-'a'],++j) { 31 for(; !go[u][s[j]-'a']&&fa[u]&&mxl[fa[u]]>=j-i; u=fa[u]); 32 if(!go[u][s[j]-'a'])break; 33 } 34 dp[i+1]=min(dp[i+1],dp[i]+p),dp[j]=min(dp[j],dp[i]+q); 35 } 36 printf("%lld\n",dp[n]); 37 } 38 return 0; 39 }
后记:我又尝试了使用后缀数组+线段树的方法,复杂度,然而这题时限卡得太死了过不去,QAQ
分类:
动态规划-数据结构优化dp
, 字符串/数据结构-后缀自动机
【推荐】还在用 ECharts 开发大屏?试试这款永久免费的开源 BI 工具!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 软件产品开发中常见的10个问题及处理方法
· .NET 原生驾驭 AI 新基建实战系列:向量数据库的应用与畅想
· 从问题排查到源码分析:ActiveMQ消费端频繁日志刷屏的秘密
· 一次Java后端服务间歇性响应慢的问题排查记录
· dotnet 源代码生成器分析器入门
· 软件产品开发中常见的10个问题及处理方法
· 互联网不景气了那就玩玩嵌入式吧,用纯.NET开发并制作一个智能桌面机器人(四):结合BotSharp
· Vite CVE-2025-30208 安全漏洞
· MQ 如何保证数据一致性?
· 《HelloGitHub》第 108 期