https://codeforces.com/contest/608/problem/D
题目大意:有一个序列,每次能清楚其中一个连续的回文序列,求把整个序列清零的最小操作次数。
思路:
这是一个区间DP,可以设DP[ i ][ j ]为把 i 到 j 区间的序列消除的最小次数。
那么,当a[ i ]==a[ j ]时可以分为两种情况:
1,i+1== j ,这时dp[ i ][ j ]=1;
2,i+1!= j ,这时dp[ i ][ j ]=dp[ i + 1 ][ j - 1 ];(因为在消除dp[ i + 1 ][ j -1 ]的过程中,势必会产生回文序列,这时可以把他和第i个和第j个一同消去)
那么当a[ i ]!=a[ j ]时,把区间分开DP即可。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<iostream> #include<cstring> #include<algorithm> #include<cstdio> #include<cmath> #include<map> #include<queue> #include<vector> #include<string> #include<time.h> #define ll long long #define PI acos(-1.0) #define F first #define S second #define pb push_back #define debug(x); printf("debug%d ",x); #define des(x); printf("des:%s ",x+1); #define rep(f,t) for(int i=f;i<=t;i++) const ll INF=0x3f3f3f3f3f3f3f3f; const int inf=0x3f3f3f3f; const ll mod=998244353; using namespace std; int n; int a[550]; int dp[600][600]; int main() { scanf("%d",&n); memset(dp,inf,sizeof dp); for(int i=1;i<=n;i++) { scanf("%d",&a[i]); dp[i][i]=1; } for(int len=2;len<=n;len++) { for(int i=1;i+len-1<=n;i++) { int j=i+len-1; if(a[i]==a[j]) { if(j==i+1) { dp[i][j]=1; } else { dp[i][j]=min(dp[i][j],dp[i+1][j-1]); } } for(int k=i;k<j;k++) { dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]); } } } printf("%d ",dp[1][n]); return 0; }