首页 > 代码库 > 【BZOJ-1090】字符串折叠 区间DP + Hash
【BZOJ-1090】字符串折叠 区间DP + Hash
1090: [SCOI2003]字符串折叠
Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 1127 Solved: 737
[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
Solution
区间DP
f[l][r]表示区间[l,r]最短折叠
那么我们枚举区间长度,枚举区间左端点,枚举断点
$f[l][r]=min(r-l+1,f[l][k]+f[k+1][r]);$
$f[l][r]=min(f[l][r],f[l][k]+2+s);$ 当区间[l,r]能被[l,k]折叠,2为括号,s为系数位数
判断的时候可以暴力判断,不过那么%来%去太鬼畜了,所以直接用个Hash
Code
#include<iostream>#include<cstring>#include<cmath>#include<cstdio>#include<algorithm>using namespace std;char S[110];int f[110][110],N;#define base 13#define ULL unsigned long longULL bin[110],hash[110];void Hashtable(){ bin[0]=1; for (int i=1; i<=N; i++) bin[i]=bin[i-1]*base; for (int i=1; i<=N; i++) hash[i]=hash[i-1]*base+S[i];}inline ULL Gethash(int l,int r) {return hash[r]-hash[l-1]*bin[r-l+1];}inline int size(int x) {int re=0; while (x) x/=10,re++; return re;}inline bool judge(int l,int m,int r){ if ((r-l+1)%m) return 0; int tl=(r-l+1)/m; ULL t=Gethash(l,l+tl-1); for (int i=l; i<=r; i+=tl) if (Gethash(i,i+tl-1)!=t) return 0; return 1;}int main(){ scanf("%s",S+1); N=strlen(S+1); Hashtable(); for (int i=1; i<=N; i++) for (int j=1; j<=N; j++) if (j+i-1<=N) { int l=j,r=j+i-1; f[l][r]=r-l+1; for (int k=1; k<=i; k++) { f[l][r]=min(f[l][r],f[l][l+k-1]+f[l+k][r]); if (judge(l,k,r)) f[l][r]=min(f[l][r],2+size(k)+f[l][l+(r-l+1)/k-1]); } } printf("%d\n",f[1][N]); return 0;}
【BZOJ-1090】字符串折叠 区间DP + Hash
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。