Live2d Test Env

CodeForces-245H:Queries for Number of Palindromes(3-14:区间DP||回文串)

Times:5000ms;

Memory limit:262144 kB

给定字符串S(|S|<=5000),下标由1开始。然后Q个问题(Q<=1e6),对于每个问题,给定L,R,回答区间[L,R]里有多少个回文串。

请想出两种或者以上的方法。

 

------------------------分界线--------------------------

 方法1:区间DP。

          容斥一下,dp[i][j]=dp[i][j-1]+dp[i+1][j]-dp[i+1][j-1]+ok[i][j],(ok表示是否是个回文串)。

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=5010;
int dp[maxn][maxn],ok[maxn][maxn],N,Q;
char c[maxn];
void DP()
{
    for(int i=N;i>=1;i--)
      for(int j=i;j<=N;j++){
         if(j-i==0) ok[i][j]=1,dp[i][j]=1;
         else if(j-i==1) dp[i][j]=ok[i][j]=dp[i][i]+dp[j][j]+(c[i]==c[j]?1:0);
         else {
            ok[i][j]=ok[i+1][j-1]&(c[i]==c[j]);
            dp[i][j]=dp[i+1][j]+dp[i][j-1]-dp[i+1][j-1]+ok[i][j];
         }
    }
}
int main()
{
    scanf("%s",c+1);
    N=strlen(c+1);
    DP();
    scanf("%d",&Q);
    while(Q--){
        int x,y; scanf("%d%d",&x,&y);
        printf("%d\n",dp[x][y]);
    }
    return 0;
}

方法2: 

        马拉车:每个为起点,然后预处理得到每个为起点的回文串个数前缀和。 为了训练,就先不给带代码了。

方法3:回文树,这个我还不会。

 

方法4:暴力,开始我以为暴力得到回文串,然后差分得到前缀和,但是前缀和涉及到了交叉问题可能会导致出错。所以,目前还不行。(不过别人说可以,那再想想)

 

 

posted @ 2018-03-14 21:00  nimphy  阅读(166)  评论(0编辑  收藏  举报