codeforces 245H 区间DP 好题
方法一:
先暴力求出每个字串是否是回文(枚举每个回文串的中间字符),保存在dp[i][j]中
再从以求的小区间滚成大区间
View Code
#include<stdio.h> #include<string.h> char s[5005]; int dp[5005][5005]; int main() { int i, j, k, x, y; int len = strlen(gets(s+1)); for(i = 1; i <= len; i++) // 枚举每个回文串的中间字符 { for(j = k = i; j >= 1 && k <= len && s[j] == s[k]; j--, k++) //串长度为奇数 dp[j][k]++; for(j = i, k = i+1; j >= 1 && k <= len && s[j] == s[k]; j--, k++) //串长度为偶数 dp[j][k]++; } for(i = 1; i <= len; i++) // 固定i, 滚动j for(j = i+1; j <= len; j++) dp[i][j] += dp[i][j-1]; for(i = 1; i <= len; i++) //固定j,滚动i for(j = i-1; j >= 1; j--) dp[j][i] += dp[j+1][i]; int Q; scanf("%d", &Q); while(Q--) { scanf("%d%d", &x, &y); printf("%d\n", dp[x][y]); } return 0; }
方法二:
区间dp, 直接从小区间推到达区间
View Code
#include<stdio.h> #include<string.h> char s[5005]; int dp[5005][5005]; //保存个数 bool f[5005][5005]; //保存f[i][j]是否是回文 int main() { int i, j, k; int len = strlen(gets(s+1)); for(i = 1; i <= len; i++) dp[i][i] = 1, f[i][i] = 1, f[i][i-1] = 1; // 注意 f[i][i-1] = 1;别忘记, len = 2时递推的时候要用到 for(int l = 2; l <= len; l++) for(i = 1, j = l; j <= len; i++, j++) { f[i][j] = f[i+1][j-1] && (s[i] == s[j]); dp[i][j] = dp[i][j-1] + dp[i+1][j] - dp[i+1][j-1] + f[i][j]; } int Q, x, y; scanf("%d", &Q); while(Q--) { scanf("%d%d", &x, &y); printf("%d\n", dp[x][y]); } return 0; }


浙公网安备 33010602011771号