【P4302 [SCOI2003]字串摺疊】題解
阿新 • • 發佈:2021-12-05
題目連結
題目
摺疊的定義如下:- 一個字串可以看成它自身的摺疊。記作S = S
- X(S)是X(X>1)個S連線在一起的串的摺疊。記作X(S) = SSSS…S(X個S)。
- 如果A = A’, B = B’,則AB = A’B’ 例如,因為3(A) = AAA, 2(B) = BB,所以3(A)C2(B) = AAACBB,而2(3(A)C)2(B) = AAACAAACBB
給一個字串,求它的最短折疊。例如AAAAAAAAAABABABCCD的最短折疊為:9(A)3(AB)CCD。
思路
區間dp
首先必然列舉中間點,然後左右合併。
也可以列舉迴圈節,然後暴力判斷。
判斷之前先看一下是否為長度的因數,如果暴力後是否能使答案更小,然後就不會被卡。
原則上時間複雜度 \(O(n^4)\),然後必然卡不滿,相當於 \(O(n^3)\) 加個小常數,最壞也就 \(O(n^3\sqrt n)\)。
tips:與UVA1351雙倍經驗哦!
Code
// Problem: UVA1351 String Compression // Contest: Luogu // URL: https://www.luogu.com.cn/problem/UVA1351 // Memory Limit: 0 MB // Time Limit: 3000 ms // // Powered by CP Editor (https://cpeditor.org) #include<bits/stdc++.h> using namespace std; //#define int long long inline int read(){int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+ (x<<3)+(ch^48);ch=getchar();}return x*f;} //#define M //#define mo #define N 210 int n, m, i, j, k; int f[N][N]; char s[N]; int l, r, len, t; int length(int x) { int ans=0; while(x) ++ans, x/=10; return ans; } int pan(int l, int r, int k) { for(i=l+k; i<=r; ++i) if(s[i]!=s[i-k]) return 0; return 1; } int check(int l, int r, int k) { if(2+f[l][l+k-1]+length(len/k)>=f[l][r]) return 999; if(pan(l, r, k)) return 2+f[l][l+k-1]+length(len/k); return 999; } signed main() { // freopen("tiaoshi.in", "r", stdin); // freopen("tiaoshi.out", "w", stdout); // t=read(); t=1; while(t--) { scanf("%s", s+1); n=strlen(s+1); for(i=1; i<=n; ++i) f[i][i]=1; for(len=2; len<=n; ++len) for(l=1, r=l+len-1; r<=n; ++l, ++r) { f[l][r]=len; for(k=l; k<r; ++k) f[l][r]=min(f[l][r], f[l][k]+f[k+1][r]); for(k=1; k*k<=len; ++k) if(len%k==0) { f[l][r]=min(f[l][r], check(l, r, k)); f[l][r]=min(f[l][r], check(l, r, len/k)); } } printf("%d\n", f[1][n]); } return 0; }