Codeforces 557E - Ann and Half-Palindrome (字典树+DP)

首先一个N方的DP处理出哪些串是半回文串。对于输出字典序第K个这种问题可以使用字典树。

先一个dfs计算出字典树中每个节点下面的子树中共有多少半回文串,然后在输出时,递归引入参数K,如果K小于左子树回文串数,说明此处应该输出a,向左走。否则要把K-=左子树回文子串数,然后输出b进右边,直到K<=0。

插入时不能一个子串一个子串插,因为插入是O(N)的,那样总时间就是N^3的了。要一次性把同一起点的所有子串都插入。


代码:

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
#define maxn 5005
char s[5005];
bool dp[5005][5005];
int ch[maxn*maxn][2];
int ed[maxn*maxn];
int num[maxn*maxn];
int sz;
void Init(){ sz=1 ; memset(ch[0],0,sizeof(ch[0])); }
int idx(char c) { return c-'a'; }
int len;
void Insert(int a){
    int u=0;
    for(int i=a;i<len;i++){
        int c=idx(s[i]);
        if(!ch[u][c]){
            ed[sz]=0;
            ch[u][c]=sz++;
        }
        u=ch[u][c];
        if(dp[a][i]) ed[u]++;
    }
}

int K;
int cur;
bool OK=0;
void Print(int n,int K){
    K-=ed[n];
    if(K<=0) return ;
    int l=ch[n][0],r=ch[n][1];
    if(l){
        if(num[l]>=K){
            printf("a");
            Print(l,K);
        }
        else{
            K-=num[l];
            printf("b");
            Print(r,K);
        }
    }
    else {
        printf("b");
        Print(r,K);
    }
}

void dfs(int n){
    if(ch[n][0]){
        dfs(ch[n][0]);
        num[n]+=num[ch[n][0]];
    }
    if(ch[n][1]){
        dfs(ch[n][1]);
        num[n]+=num[ch[n][1]];
    }
    if(ed[n]) num[n]+=ed[n];
}


int main(){
    scanf("%s",s);
    scanf("%d",&K);
    len=strlen(s);
    Init();
    for(int i=0;i<len;i++){
        dp[i][i]=1;
    }
    for(int i=0;i<len-1;i++){
        if(s[i]==s[i+1]){
            dp[i][i+1]=1;
        }
    }
    for(int i=0;i<len-2;i++){
        if(s[i]==s[i+2]){
            dp[i][i+2]=1;
        }
    }
    for(int i=0;i<len-3;i++){
        if(s[i]==s[i+3]){
            dp[i][i+3]=1;
        }
    }
    for(int i=5;i<=len;i++){
        for(int j=0;j<len-i+1;j++){
            if(dp[j+2][j+i-3]&&s[j]==s[j+i-1]){
                dp[j][j+i-1]=1;
            }
        }
    }
    for(int i=0;i<len;i++) Insert(i);
    dfs(0);
    Print(0,K);
    return 0;
}




你可能感兴趣的:(字典树,回文串)