bzoj1090[SCOI2003]字符串折叠

bzoj1090[SCOI2003]字符串折叠

题意:

折叠的定义如下:1. 一个字符串可以看成它自身的折叠。记作S。2. X(S)是X(X>1)个S连接在一起的串的折叠。记作X(S)。注意括号可以嵌套。给出字符串,求折叠后字符串的最短长度。

字符串长度≤100。

题解:

区间dp。f[i][j]=min(f[i][k]+f[k+1][j],f[i][k]+len(getnum(i,k,i,j)))。f[i][j]表示i到j的最短折叠长度。getnum(i,k,i,j)表示字符串[i..k]在字符串[i..j]中出现了几次(如果后者不是前者重复组成的返回正无穷),这个可以用哈希求。len表示一个数的长度,注意正无穷的长度为正无穷。

代码:

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #define inc(i,j,k) for(int i=j;i<=k;i++)
 5 #define maxn 110
 6 #define ll unsigned long long
 7 #define zsye 2333
 8 #define INF 0x3fffffff
 9 using namespace std;
10 
11 int f[maxn][maxn],n; ll hash[maxn],mi[maxn];
12 char str[maxn];
13 ll get(int l,int r){
14     return hash[r]-hash[l-1]*mi[r-l+1];
15 }
16 int getnum(int l1,int r1,int l2,int r2){
17     if((r2-l2+1)%(r1-l1+1)!=0)return INF; ll orzzs=get(l1,r1);
18     inc(i,1,(r2-l2+1)/(r1-l1+1))if(orzzs!=get(l2+(i-1)*(r1-l1+1),l2+i*(r1-l1+1)-1))return INF;
19     return (r2-l2+1)/(r1-l1+1);
20 }
21 int numlen(int x){if(x==INF)return INF; int tot=0; while(x)x/=10,tot++; return tot;}
22 void dfs(int l,int r){
23     if(f[l][r]!=-1)return; inc(i,l,r-1)dfs(l,i),dfs(i+1,r); f[l][r]=INF;
24     inc(i,l,r-1)f[l][r]=min(f[l][r],f[l][i]+f[i+1][r]);
25     inc(i,l,r)f[l][r]=min(f[l][r],f[l][i]+2+numlen(getnum(l,i,l,r)));
26 }
27 int main(){
28     scanf("%s",str+1); n=strlen(str+1); mi[0]=1;
29     inc(i,1,n)hash[i]=hash[i-1]*zsye+str[i],mi[i]=mi[i-1]*zsye;
30     memset(f,-1,sizeof(f)); inc(i,1,n)f[i][i]=1;
31     dfs(1,n); printf("%d",f[1][n]); return 0;
32 }

 

20161110

posted @ 2016-11-11 19:23  YuanZiming  阅读(398)  评论(0编辑  收藏  举报