题目链接:https://codeforces.com/contest/608/problem/D
题意:给出n个宝石的颜色ci,现在有一个操作,就是子串的颜色是回文串的区间可以通过一次操作消去,问最少需要多少次操作可以消除所有的宝石。(每次操作消除一个回文串,最少操作次数清楚字符串)
题解:dp[l][r]表示区间(l,r)的最少操作次数,对于一个区间(l,r),有两种转移:①若存在c_l = c_i(l <= i <= r),可以由dp[l][i] + dp[i + 1][r]转移;②若c_l = c_r,可以由dp[l + 1][r - 1]转移。
1 #include <bits/stdc++.h> 2 using namespace std; 3 #define ll long long 4 #define ull unsigned long long 5 #define mst(a,b) memset((a),(b),sizeof(a)) 6 #define mp(a,b) make_pair(a,b) 7 #define pi acos(-1) 8 #define pii pair<int,int> 9 #define pb push_back 10 #define lowbit(x) ((x)&(-x)) 11 const int INF = 0x3f3f3f3f; 12 const double eps = 1e-6; 13 const int maxn = 510 + 10; 14 const int maxm = 1e6 + 10; 15 const ll mod = 998244353; 16 17 int c[maxn]; 18 int dp[maxn][maxn]; 19 20 int main() { 21 #ifdef local 22 freopen("data.txt", "r", stdin); 23 // freopen("data.txt", "w", stdout); 24 #endif 25 int n; 26 scanf("%d",&n); 27 for(int i = 0; i < n; i++) { 28 scanf("%d",&c[i]); 29 dp[i][i] = 1; 30 } 31 for(int i = 0; i < n - 1; i++) { 32 if(c[i] == c[i + 1]) dp[i][i + 1] = 1; 33 else dp[i][i + 1] = 2; 34 } 35 for(int i = 2; i < n; i++) { 36 for(int j = 0; i + j < n; j++) { 37 dp[j][j + i] = i + 1; 38 for(int k = j; k < j + i; k++) { 39 if(c[j] == c[k]) dp[j][j + i] = min(dp[j][j + i], dp[j][k] + dp[k + 1][j + i]); 40 } 41 if(c[j] == c[j + i]) dp[j][j + i] = min(dp[j][j + i], dp[j + 1][j + i - 1]); 42 } 43 } 44 printf("%d ",dp[0][n - 1]); 45 return 0; 46 }