回文 (dp)

来源:互联网 发布:js有哪些内置对象 编辑:程序博客网 时间:2024/06/06 00:09

回文(pal.c/cpp/pas)

1 题目描述
闲着无聊的YGH秒掉上面两道题之后,开始思考有趣的回文串问题了。
他面前就有一个漂浮着的字符串。显然YGH是会manacher的,于是他随手求出了这个字符串的回文子串个数。但是他不满足于这个问题,他打算搞出一个数据结构,能够快速求出这个字符串下标为[l,r]的子串的回文子串个数(相同的回文子串需重复计数)。但是这实在是太简单啦,他打算考考辣鸡YYR,可是辣鸡至极的YYR完全没有思路。
于是,YGH扬长而去,在衣袖带起的一小片尘土之中,沉思的YYR依旧在那里。
2 输入格式
第一行为一个字符串S。
第二行一个整数T,表示询问次数。
接下来T行,每行两个整数l、r,表示查询字符串S下标为[l,r]的子串的答案。
3 输出格式
输出T行,每行一个整数表示这个询问的答案。
样例输入
ababaab
2
1 3
3 7
样例输出
4
8
数据范围与约定
对于20%的数据,保证 |S| , T<=500
对于40%的数据,保证 |S| , T <=5000
对于100%的数据,保证 |S| <=5000 , T<=100000

思路:
神奇的dp,本来还以为良心的YYR释放了善意。。。
前20%的数据:大暴力
前40%的数据:每次跑一遍manacher,计算这个子串的回文子串数,复杂度O(n*T)。
前100%的数据:考虑DP,先处理出g[i][j]表示i到j这一段是否为回文串,很容易通过g[i+1][j-1]推得。再用f[i][j]表示i到j这一个子串的回文子串数,那么f[i][j]=f[i+1][j]+f[i][j-1]-f[i+1][j-1]+g[i][j]。再处理一下边界情况就好。复杂度O(n^2+T)。
对了,这个数据结构就是二维数组。

#include <cstdio>#include <ctime>#include <cstring>#include <cstdlib>#include <algorithm>using namespace std;char s[5050];int dp[5050][5050];bool f[5050][5050];int q, len;bool check(int l, int r){    if (f[l][r]) return true;    else  return f[l][r] = ( (s[l]==s[r]) && check(l+1,r-1) );}void solve(){    int k, i, j;    for(int i=0; i<len; i++){        dp[i][i] = 1; dp[i][i+1] = 2;        f[i][i] = true;        if(s[i] == s[i+1]){            dp[i][i+1]++;             f[i][i+1] = true;        }    }    for(int k=2; k<len; k++){        for(int j=k,i=0; j<len; i++,j++){            dp[i][j] = dp[i][j-1] + dp[i+1][j] - dp[i+1][j-1];            if( check(i, j) ) dp[i][j]++;        }    }}int main(){    freopen("pal.in","r",stdin) ;    freopen("pal.out","w",stdout) ;    int r, l;    scanf("%s", s); len = strlen(s);    scanf("%d", &q);    memset(f, false, sizeof(f));    memset(dp, 0, sizeof(dp));    solve();    for(int i=0; i<q; i++){        scanf("%d %d", &l, &r);        printf("%d\n", dp[l-1][r-1]);    }    return 0;}