P3426-[POI2005]SZA-Template【KMP】
正題
題目鏈接:https://www.luogu.com.cn/problem/P3426
題目大意
給出一個長度為nnn的字符串sss,求一個長度最小的字符串ttt使得sss所有ttt和ttt匹配的位置能覆蓋串sss。
1≤n≤5×1051\leq n\leq 5\times 10^51≤n≤5×105
解題思路
首先答案肯定是原串的一個borderborderborder,設fif_ifi?表示前綴s1~is_{1\sim i}s1~i?的答案。
考慮如何轉(zhuǎn)移,首先fif_ifi?至多是iii,然后考慮如果有一個串ttt能夠覆蓋s1~nxtis_{1\sim nxt_i}s1~nxti??那么才有可能能覆蓋s1~is_{1\sim i}s1~i?。(因為如果覆蓋大于nxtinxt_inxti?顯然不可能覆蓋整個串,不然就至少需要覆蓋到s1~nxtis_{1\sim nxt_i}s1~nxti??)。
考慮什么時候fif_ifi?能夠取到fnxtif_{nxt_i}fnxti??。首先我們可以表示出s1,nxtis_{1,nxt_i}s1,nxti??假設我們上次覆蓋的位置是j∈[nxti,i]j\in[nxt_i,i]j∈[nxti?,i],那么需要有fj=fnxtif_{j}=f_{nxt_i}fj?=fnxti??(即取到同一個borderborderborder),然后要求j≥i?nxtij\geq i-nxt_ij≥i?nxti?(這樣就可以用s1,nxtis_{1,nxt_i}s1,nxti??覆蓋剩下的)。
時間復雜度O(n)O(n)O(n)
code
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N=5e5+10; int n,f[N],nxt[N],ls[N]; char s[N]; int main() {scanf("%s",s+1);n=strlen(s+1);for(int i=2,j=0;i<=n;i++){while(j&&s[j+1]!=s[i])j=nxt[j];j+=(s[i]==s[j+1]);nxt[i]=j;}for(int i=1;i<=n;i++){f[i]=i;if(i-ls[f[nxt[i]]]<=nxt[i])f[i]=f[nxt[i]];ls[f[i]]=i;}printf("%d\n",f[n]);return 0; }總結
以上是生活随笔為你收集整理的P3426-[POI2005]SZA-Template【KMP】的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ps线稿怎么上色(ps线稿怎么上色不涂到
- 下一篇: ps高斯模糊后怎么去掉波纹(ps高斯模糊