[BZOJ] 1090 [SCOI2003]字符串摺疊

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 1909  Solved: 1251
[Submit][Status][Discuss]
Description
摺疊的定義如下: 1. 一個字符串可以看成它自身的摺疊。記作S  S 2. X(S)是X(X>1)個S連接在一起的串的摺疊。記作X(S)  SSSS…S(X個S)。 3. 如果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。

Input
僅一行,即字符串S,長度保證不超過100。

Output
僅一行,即最短的摺疊長度。

Sample Input
NEERCYESYESYESNEERCYESYESYES
Sample Output
14
HINT
一個最短的摺疊爲:2(NEERC3(YES))

Source

字符串上做區間dp,很像hnoi的玩具取名的感覺。

雖然len最長只有100,但這不代表二維不能做。
還是枚舉[l,r]的劃分點,大區間依賴小區間,縮點思想。
唯一不同的一點是,更新除了由小區間更新,還可以判斷自己是否循環,(KMP也可以做),所幸本題數據不大,暴力判斷就行。

循環的話就是循環節長度+2(括號)+dig(循環次數),dig代表位數。
更新 SQY大兄弟說判斷循環節,只需要判到串長一半,再長一定不優,確實是這樣的。

#include<iostream>
#include<cstdio>
#include<cstring>

using namespace std;

char s[105];
int len;

int dig(int x) {return x<=9?1:dig(x/10)+1;}

bool pd(int x,int y,int z) {
    for(int i=1;i<=len;i++){
        for(int j=x+i-1;j+z<=y;j+=z){
            if(s[j]!=s[j+z]) return false;
        }
    }
    return true;
}
int f[105][105];

int main() {
    memset(f,0x3f,sizeof(f));
    scanf("%s",s+1);
    len=strlen(s+1);
    for(int i=0;i<=len;i++) f[i][i]=1;
    for(int l=0; l<=len; l++) {
        for(int i=1; i+l<=len; i++) {
            int j=i+l;
            for(int k=1; k<=j-i+1; k++) {
                if((j-i+1)%k==0&&pd(i,j,k)) f[i][j]=min(f[i][j],2+f[i][i+k-1]+dig((j-i+1)/k));
            }
            for(int k=i; k<j; k++) {
                f[i][j]=min(f[i][j],f[i][k]+f[k+1][j]);
            }

        }
    }
    cout<<f[1][len];
}
發佈了180 篇原創文章 · 獲贊 6 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章