UVA-1630 Folding (KMP、区间dp)

Folding
Time Limit: 3000MS   Memory Limit: Unknown   64bit IO Format: %lld & %llu

Submit Status

Description

Bill is trying to compactly represent sequences of capital alphabetic characters from `A' to `Z' by folding repeating subsequences inside them. For example, one way to represent a sequence `AAAAAAAAAABABABCCD' is `10(A)2(BA)B2(C)D'. He formally defines folded sequences of characters along with the unfolding transformation for them in the following way: 

  • A sequence that contains a single character from `A' to `Z' is considered to be a folded sequence. Unfolding of this sequence produces the same sequence of a single character itself. 
  • If S and Q are folded sequences, then SQ is also a folded sequence. If S unfolds to S' and Q unfolds to Q', then SQ unfolds to S'Q'
  • If S is a folded sequence, then X(S) is also a folded sequence, where X is a decimal representation of an integer number greater than 1. If S unfolds to S', then X(S) unfolds to S' repeated X times. 

According to this definition it is easy to unfold any given folded sequence. However, Bill is much more interested in the reverse transformation. He wants to fold the given sequence in such a way that the resulting folded sequence contains the least possible number of characters. 

Input 

Input file contains several test cases, one per line. Each of them contains a single line of characters from `A' to `Z' with at least 1 and at most 100 characters. 

Output 

For each input case write a different output line. This must be a single line that contains the shortest possible folded sequence that unfolds to the sequence that is given in the input file. If there are many such sequences then write any one of them. 

Sample Input 

AAAAAAAAAABABABCCD
NEERCYESYESYESNEERCYESYESYES

Sample Output 

9(A)3(AB)CCD
2(NEERC3(YES))


题意:

给出一个字符串,折叠成一个尽量短的串,串的每一个字符都算作长度。

分析:

借鉴自:http://www.cnblogs.com/AOQNRMGYXLMV/p/4781849.html

用d[i][j]表示i-j区间内最短字符串,进行状态更新。

思路很简单,但实现起来技巧很多,借鉴了大神的代码。

先是温习了一下KMP,然后发现自己想法和写法和别人的比都太逗了,就按照大神思路抄了下来。

按长度从小到大对字符串的子串进行简化,然后合并更新,最后得到最大串。其中KMP主要是对不同长度的子串进行处理,找到子串结尾的next数组对应大小,根据KMP思想可以得到对于长度为L的字符串,next[L+1]得到的恰好是第L个字符所对应的前一个字符(因为字符串是从0开头的),所以L-next(L+1)就是该子串中重复次数最高的子子串的长度大小(模拟一下就明白了)。

然后就是区间更新合并,思路不难,实现有点技巧,值得学习。

#include <algorithm>
#include <iostream>
#include <sstream>
#include <cstring>
#include <cstdlib>
#include <string>
#include <fstream>
#include <vector>
#include <cstdio>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
using namespace std;
#define INF 0x3f3f3f3f
const int N=105;
const int mod=1e9+7;

int nex[N];
char s[N],t[N];
string d[N][N];

string ToString(int x) {
    string ans="";
    while (x) {
        ans+=(char)('0'+x%10);
        x/=10;
    }
    reverse(ans.begin(), ans.end());
    return ans;
}

void getNext(char *b) {
    nex[0]=nex[1]=0;
    int len=strlen(b);
    int j=0;
    for (int i=1; i<len; i++) {
        while (j>0&&b[i]!=b[j]) j=nex[j];
        if (b[i]==b[j]) j++;
        nex[i+1]=j;
    }
}

int main() {
    while (scanf("%s",&s)==1) {
        int len=strlen(s);
        for (int i=0; i<len; i++) d[i][i]=string("")+s[i];
        
        for (int l=2; l<=len; l++) {
            for (int i=0; i+l-1<len; i++) {
                int j=i+l-1;
                d[i][j]="";
                for (int k=i; k<=j; k++) {
                    d[i][j]+=s[k];
                    t[k-i]=s[k];
                }
                t[j-i+1]='/0';
                getNext(t);
                if (l%(l-nex[l])==0) {
                    int cycle=l-nex[l];
                    string x=ToString(l/cycle);
                    x+='(';
                    x+=d[i][i+cycle-1];
                    x+=')';
                    if (x.length()<d[i][j].length()) {
                        d[i][j]=x;
                    }
                }
                
                for (int k=i; k<j; k++) {
                    if (d[i][k].length()+d[k+1][j].length()<d[i][j].length()) {
                        d[i][j]=d[i][k]+d[k+1][j];
                    }
                }
            }
        }
        cout<<d[0][len-1]<<endl;
    }
    return 0;
}


你可能感兴趣的:(UVA-1630 Folding (KMP、区间dp))