您的位置:首页 > 其它

BZOJ1090 [SCOI2003]字符串折叠

2017-10-10 09:58 267 查看
标签:区间DP
Description
 S 2. X(S)是X(Xà折叠的定义如下: 1. 一个字符串可以看成它自身的折叠。记作S>AAACAAACBB 给一个字符串,求它的最短折叠。例如AAAAAAAAAABABABCCD的最短折叠为:9(A)3(AB)CCD。àAAACBB,而2(3(A)C)2(B)à A’B’ 例如,因为3(A)
= AAA, 2(B) = BB,所以3(A)C2(B) àB’,则AB àA’, Bà SSSS…S(X个S)。 3. 如果A à1)个S连接在一起的串的折叠。记作X(S)

Input
仅一行,即字符串S,长度保证不超过100。
Output
仅一行,即最短的折叠长度。
Sample Input
NEERCYESYESYESNEERCYESYESYES
Sample Output
14
HINT
一个最短的折叠为:2(NEERC3(YES))
和SCOI07 压缩很相似

记忆化搜索,dp(l,r)表示làr的最短长度

经典的区间DP方程dp(l,r)=min{dp(l,i)+dp(i+1,r)}l<=i<r

但是要考虑到该子串内部是否可以合并的问题

用ablej判断从lài与i+1àr是否可以合并,用calc计算合并后十进制数字的位数

 

Code

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define dep(i,a,b) for(int i=a;i>=b;i--)
#define LL long long
#define mem(x,num) memset(x,num,sizeof x)
using namespace std;
const int maxn=106,inf=0x3f3f3f;
char s[maxn];
bool mark[maxn][maxn];
int f[maxn][maxn],len;

inline int calc(int x){int y=0;while(x){x/=10;y++;}return y;}

bool ablej(int l,int r,int L,int R){
if(((R-L+1)%(r-l+1))!=0)return 0;
rep(i,L,R)
if(s[i]!=s[l+((i-L)%(r-l+1))])return 0;
return 1;
}

int dp(int l,int r)
{
if(l==r)return 1;
if(mark[l][r])return f[l][r];
mark[l][r]=1;
int t=r-l+1;
rep(i,l,r-1){
t=min(t,dp(l,i)+dp(i+1,r));
if(ablej(l,i,i+1,r))t=min(t,dp(l,i)+2+calc(((r-i)/(i-l+1))+1));
}
return f[l][r]=t;
}

int main()
{
scanf("%s",s);
len=strlen(s);
printf("%d\n",dp(0,len-1));
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  动态规划 bzoj