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;
}

 

 

posted @ 2012-11-22 20:56  To be an ACMan  Views(773)  Comments(0)    收藏  举报