P4302-[SCOI2003]字符串折叠【区间dp】
生活随笔
收集整理的這篇文章主要介紹了
P4302-[SCOI2003]字符串折叠【区间dp】
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
正題
題目鏈接:https://www.luogu.com.cn/problem/P4302
題目大意
一個字符串,對于一個字符串AAA??梢詫⑦B續的nnn個AAA縮成n(A)n(A)n(A)。求最短的長度能夠表述出給定字符串
解題思路
定義fi,jf_{i,j}fi,j?表示表示出i~ji\sim ji~j的字符串的最短方法。那么不考慮折疊的話有正常區間dpdpdp轉移即fi,j=min{fi,k+fk+1,j}(i≤k<j)f_{i,j}=min\{f_{i,k}+f_{k+1,j}\}(i\leq k<j)fi,j?=min{fi,k?+fk+1,j?}(i≤k<j)
然后對于一段區間[l,r][l,r][l,r]考慮折疊,我們枚舉長度lenlenlen的約數kkk,判斷能否用長度為kkk的字符串折疊。有轉移fi,j=min{fi,i+k?1+2+zlen/k}(k?>[i,j])f_{i,j}=min\{f_{i,i+k-1}+2+z_{len/k}\}(k->[i,j])fi,j?=min{fi,i+k?1?+2+zlen/k?}(k?>[i,j])(ziz_izi?表示iii的位數)
時間復雜度O(n3n)O(n^3\sqrt n)O(n3n?)
codecodecode
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; int n,z[110],f[110][110]; char s[110]; bool check(int l,int r,int len){if((r-l+1)%len!=0)return 0;for(int i=l+len;i<=r;i++)if(s[i-len]!=s[i])return 0;return 1; } int main() {scanf("%s",s+1);n=strlen(s+1);memset(f,0x3f,sizeof(f));for(int i=1;i<=n;i++)z[i]=z[i/10]+1,f[i][i]=1;for(int l=2;l<=n;l++){for(int i=1;i+l-1<=n;i++){int j=i+l-1;for(int k=i;k<j;k++)f[i][j]=min(f[i][j],f[i][k]+f[k+1][j]);for(int k=1;k<l;k++)if(check(i,j,k))f[i][j]=min(f[i][j],f[i][i+k-1]+2+z[l/k]);}}printf("%d",f[1][n]); }總結
以上是生活随笔為你收集整理的P4302-[SCOI2003]字符串折叠【区间dp】的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 塔娜花日个人资料简历 塔娜花日简介
- 下一篇: 腕组词腕的组词腕字怎么组词