bzoj 1068: [SCOI2007]壓縮1068: [SCOI2007]壓縮
阿新 • • 發佈:2018-11-27
1068: [SCOI2007]壓縮1068: [SCOI2007]壓縮
給一個由小寫字母組成的字串,我們可以用一種簡單的方法來壓縮其中的重複資訊。壓縮後的字串除了小
寫字母外還可以(但不必)包含大寫字母R與M,其中M標記重複串的開始,R重複從上一個M(如果當前位置左邊沒
有M,則從串的開始算起)開始的解壓結果(稱為緩衝串)。 bcdcdcdcd可以壓縮為bMcdRR,下面是解壓縮的過程
另一個例子是abcabcdabcabcdxyxyz可以被壓縮為abcRdRMxyRz。
輸入僅一行,包含待壓縮字串,僅包含小寫字母,長度為n。
長度不超過50.
思路。
我們可以用 f[i][j][0/1]來表示i 到 j 之間,有沒有用放 M。
一開始。
f[i][j][0] = j - i + 1;
f[i][j][1] = j - i + 1;
接著狀態轉移。
f[i][j][0] = min(f[i][j][0],f[i][k][0] + j - k),
這個是不放M 的。
f[i][j][1] = min(f[i][j][1],min(f[i][k][1],f[i][k][0]) + min(f[k+1][j][1],f[k+1][j][0]) + 1);
這個是在第k個位置放了M。
還有一個放 R 的。
f[i][j][0] = f[i][(i+j)/2][0] + 1
這個我們要判斷一下,i 到j 之間是不是偶數,還有是不是重複的。
#include<bits/stdc++.h> using namespace std; char s[100]; int f[100][100][2]; bool check(int x, int y){ if ((y-x+1) & 1) return 0; int mid = (x + y) / 2; for (int i = 1; i <= mid - x + 1; i++) if (s[x + i - 1] != s[mid + i]) return 0; return 1; } int main(){ int len; scanf("%s",s+1); len = strlen(s+1); for (int i = len; i > 0; i--){ for (int j = i; j <= len; j++){ f[i][j][0] = j - i + 1; f[i][j][1] = j - i + 1; for (int k = i; k < j; k++) f[i][j][0] = min(f[i][j][0],f[i][k][0] + j - k); for (int k = i; k < j; k++) f[i][j][1] = min(f[i][j][1],min(f[i][k][1],f[i][k][0]) + min(f[k+1][j][1],f[k+1][j][0]) + 1); if (check(i,j)) f[i][j][0] = f[i][(i+j)/2][0] + 1; } } printf("%d\n",min(f[1][len][0],f[1][len][1])); return 0; }