1. 程式人生 > >B1068 [SCOI2007]壓縮 區間dp

B1068 [SCOI2007]壓縮 區間dp

har ostream string border 我們 for using getchar() rip

這個題我狀態想對了,但是轉移錯了。。。dp的代碼難度都不大,但是思考含量太高了。。不會啊,我太菜了。

其實這個題就是一個正常的區間dp,中間多了一個特判的轉移就行了。

題幹:

Description

  給一個由小寫字母組成的字符串,我們可以用一種簡單的方法來壓縮其中的重復信息。壓縮後的字符串除了小
寫字母外還可以(但不必)包含大寫字母R與M,其中M標記重復串的開始,R重復從上一個M(如果當前位置左邊沒
有M,則從串的開始算起)開始的解壓結果(稱為緩沖串)。 bcdcdcdcd可以壓縮為bMcdRR,下面是解壓縮的過程

技術分享圖片

  另一個例子是abcabcdabcabcdxyxyz可以被壓縮為abcRdRMxyRz。

Input

  輸入僅一行,包含待壓縮字符串,僅包含小寫字母,長度為n。

Output

  輸出僅一行,即壓縮後字符串的最短長度。

Sample Input

bcdcdcdcdxcdcdcdcd

Sample Output

12

HINT

在第一個例子中,解為aaaRa,在第二個例子中,解為bMcdRRxMcdRR。

【限制】

100%的數據滿足:1<=n<=50 100%的數據滿足:1<=n<=50

代碼:

#include<iostream>
#include<cstdio>
#include
<cmath> #include<ctime> #include<queue> #include<algorithm> #include<cstring> using namespace std; #define duke(i,a,n) for(int i = a;i <= n;i++) #define lv(i,a,n) for(int i = a;i >= n;i--) #define clean(a) memset(a,0,sizeof(a)) const int INF = 1 << 30
; typedef long long ll; typedef double db; template <class T> void read(T &x) { char c; bool op = 0; while(c = getchar(), c < 0 || c > 9) if(c == -) op = 1; x = c - 0; while(c = getchar(), c >= 0 && c <= 9) x = x * 10 + c - 0; if(op) x = -x; } template <class T> void write(T x) { if(x < 0) putchar(-), x = -x; if(x >= 10) write(x / 10); putchar(0 + x % 10); } char s[100]; int n; int f[100][100][3]; bool check(int l,int r) { int mid = (l + r) >> 1; duke(i,1,mid - l + 1) { if(s[l + i - 1] != s[mid + i]) return 0; } return 1; } int main() { scanf("%s",s + 1); n = strlen(s + 1); lv(i,n,1) { duke(j,i,n) { f[i][j][0] = f[i][j][1] = j - i + 1; duke(k,i,j - 1) f[i][j][1] = min(f[i][j][1],min(f[i][k][0],f[i][k][1]) + 1 + min(f[k + 1][j][1],f[k + 1][j][0])); duke(k,i,j - 1) f[i][j][0] = min(f[i][j][0],f[i][k][0] + j - k); if((j - i + 1) % 2 == 0 && check(i,j)) f[i][j][0] = f[i][(i + j) / 2][0] + 1; } } printf("%d\n",min(f[1][n][0],f[1][n][1])); return 0; }

B1068 [SCOI2007]壓縮 區間dp