日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

P5404-[CTS2019]重复【KMP,dp】

發布時間:2023/12/3 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 P5404-[CTS2019]重复【KMP,dp】 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

正題

題目鏈接:https://www.luogu.com.cn/problem/P5404


題目大意

給出一個字符串SSS,然后求有多少個長度為mmm的串TTT滿足。無限多個串TTT拼接起來后能找出一個長度和SSS相等的子串字典序比SSS小。

1≤∣S∣,m≤20001\leq |S|,m\leq 20001S,m2000


解題思路

首先有一個小于的很難找,所以我們找有多少一直大于等于的減去就好了。

然后其實如果有一個大于位置大于SSS串匹配就可以直接不管,所以其實我們主要考慮前面都相等的情況,(根據題解)考慮用KMPKMPKMP

設我們現在匹配到[1,k][1,k][1,k],然后有[1,nxtk]=[k?nxtk+1,k][1,nxt_k]=[k-nxt_k+1,k][1,nxtk?]=[k?nxtk?+1,k],然后加了一個字符如果有跳的邊而且是轉移邊里面字符最大的,因為我們顯然需要匹配出一個最大的前綴不然不能保證有小于的時候能直接找到。

而且如果我們現在在KMPKMPKMP上走了T∞T^{\infty}T之后節點是iii,那么T∞TT^{\infty}TTT也是會匹配回到節點iii的,所以相當于我們要找一個節點ppp使得它匹配了TTT之后仍然是回到節點ppp

暴力枚舉節點來dpdpdp肯定是會TTT,考慮優化一下。

不難發現如果一個點走mmm步之后沒有回到過000號節點的話方案只有一種(因為每個點連接000以外的出邊最多只有一條)。

所以設fi,jf_{i,j}fi,j?表示從000出發走jjj步到達iii的方案數。

然后對于起點枚舉多少步后走到000再用fff統計答案就好了。

時間復雜度O(nm)O(nm)O(nm)


code

#include<cstdio> #include<cstring> #include<algorithm> #define ll long long using namespace std; const ll N=2100,P=998244353; ll n,m,ans,nxt[N],ch[N][26],f[N][N],mx[N]; char s[N]; signed main() {scanf("%lld%s",&m,s+1);n=strlen(s+1);ans=1;for(ll i=1;i<=m;i++)ans=ans*26ll%P;for(ll i=2,j=0;i<=n;i++){while(j&&s[i]!=s[j+1])j=nxt[j];j+=(s[i]==s[j+1]);nxt[i]=j;}for(ll i=0;i<=n;i++)for(ll c=0;c<26;c++){if(s[i+1]==c+'a')ch[i][c]=i+1;else ch[i][c]=ch[nxt[i]][c];if(ch[i][c])mx[i]=c; }f[0][0]=1;for(ll i=0;i<m;i++)for(ll j=0;j<=n;j++)for(ll c=mx[j];c<26;c++)(f[ch[j][c]][i+1]+=f[j][i])%=P;for(ll i=0;i<=n;i++){ll x=i;for(ll j=1;j<=m;j++){(ans-=(25-mx[x])*f[i][m-j]%P)%=P;x=ch[x][mx[x]];if(!x)break;}if(i&&x==i)(ans+=P-1)%=P;}printf("%lld\n",(ans+P)%P);return 0; }

總結

以上是生活随笔為你收集整理的P5404-[CTS2019]重复【KMP,dp】的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。