Codeforces 607B Zuma
题意:给你一个长度为n的字符串,每次你可以消去一段连续的回文子串,剩下的两端重新拼接成一个新的串,问最少需要消去多少次。
思路:这题一开始想不出,不好dp,一个明显的思路是用dp[i][j]表示消去i到j段最少要的次数,但是不知道每次消去后剩下的串的回文串情况,所以我们要换一个思路。其实题目中的回文串已经提醒我们字符串中的每一个字符都要和别的字符匹配后才能消除,那么对于dp[i][j],我们考虑左端点,它被消去只有两种情况,一种是单独消去,另一种是和别的字符匹配消去,第一种情况比较简单,那么对于第二种情况,我们可以枚举[i,j]区间内每一个和它相同的点k,然后先消去区间[i+1,k-1],最后再消去i和k,其实[i+1,k-1]中最后消去的肯定是回文串,一个回文串两端加两个相同的点也是回文串,可以一次消去,所以这里dp[i][j]=min(dp[i][j],dp[i+1][k-1]+dp[k+1][j]);注意还要特判k=i+1的情况。
---------Kirito_Acmer
#include<cstdio> #include<algorithm> #include<string.h> #include<stdlib.h> #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 using namespace std; typedef long long LL; int a[505],dp[505][505]; int main() { int n; while(~scanf("%d",&n)) { for(int i =0;i<n;i++) scanf("%d",&a[i]); memset(dp,0x3f,sizeof(dp)); for(int i=0;i<n;i++)dp[i][i]=1; for(int l=2;l<=n;l++){ for(int i=0;i+l-1<n;i++) { int j=i+l-1; if(a[i]==a[j]&&l>2) dp[i][j]=dp[i+1][j-1]; else if(a[i]==a[j]) dp[i][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\n",dp[0][n-1]); } }