cdqz2017-test10-加帕里图书馆(区间DP & 简单容斥)

给定一个由小写字母组成的字符串,输出有多少重复的回文子序列

#include<cstdio>
#include<cstring>

using namespace std;

#define N 2002

const int mod=1e9+7;

int n;
char s[N];

int f[N][N],g[N][N];

int pre[N][26],nxt[N][26];

int get_f(int l,int r)
{
    if(l>r) return 1;
    int &ans=f[l][r];
    if(ans!=-1) return ans;
    if(s[l]==s[r]) ans=get_f(l+1,r)+get_f(l,r-1);
    else ans=get_f(l+1,r)+get_f(l,r-1)-get_f(l+1,r-1);
    ans%=mod;
    if(ans<0) ans+=mod;
    return ans;
}

int get_g(int l,int r)
{
    if(l==r) return 2;
    if(l>r) return 1;
    int &ans=g[l][r];
    if(ans!=-1) return ans;
    if(s[l]!=s[r]) ans=get_g(l+1,r)+get_g(l,r-1)-get_g(l+1,r-1);
    else
    {
        if(nxt[l][s[l]-'a']>=r && pre[r][s[r]-'a']<=l) ans=get_g(l+1,r-1)*2+1;
        else if(nxt[l][s[l]-'a']==pre[r][s[r]-'a']) ans=get_g(l+1,r-1)*2;
        else ans=get_g(l+1,r-1)*2-get_g(nxt[l][s[l]-'a']+1,pre[r][s[r]-'a']-1);
    }
    ans%=mod;
    if(ans<0) ans+=mod;
    return ans;
}

void cal()
{
    for(int i=1;i<=n;++i)
    {
        for(int j=i+1;j<=n;++j)
            if(!nxt[i][s[j]-'a']) nxt[i][s[j]-'a']=j;
        for(int j=i-1;j;--j)
            if(!pre[i][s[j]-'a']) pre[i][s[j]-'a']=j;
    }
}

int main()
{
    freopen("library.in","r",stdin);
    freopen("library.out","w",stdout);
    scanf("%s",s+1);
    n=strlen(s+1);
    memset(f,-1,sizeof(f));
    int all=get_f(1,n);
    cal();
    memset(g,-1,sizeof(g));
    int dif=get_g(1,n);
    int ans=all-dif;
    if(ans<0) ans+=mod;
    printf("%d",ans);
}

爆搜代码

#include<cstdio>
#include<cstring>

using namespace std;

int n;
char s[2002];

char tt[2002],t[2002];
int L;

int ans,sum;

int cnt[27];

void find(int now,int len,int ok)
{
    if(ok==len) 
    {
        sum++;
        return;
    }
    for(int i=now+1;i<=n;++i)
        if(t[ok+1]==s[i]) find(i,len,ok+1);
}

void dfs(int len) 
{
    for(int i=0;i<26;++i)
    {
        tt[len]=char(i+'a');
        L=0;
        for(int j=len;j;--j) t[++L]=tt[j];
        for(int j=2;j<=len;++j) t[++L]=tt[j];
        sum=0;
        find(0,L,0);
        if(sum>1) ans+=sum-1;
        if(sum) dfs(len+1);
    }
}

void dfs2(int len)
{
    for(int i=0;i<26;++i)
    {
        tt[len]=char(i+'a');
        L=0;
        for(int j=len;j;--j) t[++L]=tt[j];
        for(int j=1;j<=len;++j) t[++L]=tt[j];
        sum=0;
        find(0,L,0);
        if(sum>1) ans+=sum-1;
        if(sum) dfs2(len+1);
    }
}

int main()
{
    freopen("library.in","r",stdin);
    freopen("library.out","w",stdout);
    scanf("%s",s+1);
    n=strlen(s+1);
    for(int i=1;i<=n;++i) cnt[s[i]-'a']++;
    dfs(1);
    dfs2(1);
    printf("%d",ans);
}
原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/8719474.html