[字典树] Codeforces 557E Ann and Half-Palindrome

来源:互联网 发布:巴西经济现状数据 编辑:程序博客网 时间:2024/05/01 09:05

题意:

给一个长度为5000的ab串,问你第k大的半回文子串是什么

所谓的半回文串就是下标是奇数的位置前后相等就好了。

思路:

首先发现串的长度只有5000,可以做一个类似区间dp的预处理

处理出dp[i][j]代表第i到j子串是不是半回文子串

然后依次把原串的所有子串插入字典树,并在节点标记个数

然后最后dfs一下k个就好了

代码:

#include"cstdlib"#include"cstdio"#include"cstring"#include"cmath"#include"queue"#include"algorithm"#include"iostream"using namespace std;#define N 20000007char v[5555],ans[5555];int dp[5555][5555],k;struct Trie{    int next[N][2],mark[N];    int root,L;    int newnode()    {        memset(next[L],-1,sizeof(next[L]));        mark[L++]=0;        return L-1;    }    void go()    {        L=0;        root=newnode();    }    void init(int l,int r)    {        int p=root;        for(int i=l; i<=r; i++)        {            int tep=v[i]-'a';            if(next[p][tep]==-1) next[p][tep]=newnode();            p=next[p][tep];            if(dp[l][i]) mark[p]++;        }    }    void dfs(int x,int y)    {        if(k-mark[x]>0)        {            k-=mark[x];            for(int i=0; i<2; i++)            {                ans[y]='a'+i;                if(next[x][i]!=-1) dfs(next[x][i],y+1);                if(k<=0) return ;            }        }        else        {            k-=mark[x];            ans[y]='\0';            return ;        }    }} ac;int main(){    while(scanf("%s",v)!=-1)    {        scanf("%d",&k);        int len=strlen(v);        for(int i=0;i<len;i++) for(int j=0;j<len;j++) dp[i][j]=0;        for(int i=0; i<len; i++)        {            dp[i][i]=1;            if(v[i]==v[i+1]) dp[i][i+1]=1;            if(v[i]==v[i+2]) dp[i][i+2]=1;            if(v[i]==v[i+3]) dp[i][i+3]=1;        }        for(int i=4; i<len; i++) for(int j=0; j+i<len; j++) if(v[j]==v[j+i]&&dp[j+2][j+i-2]) dp[j][j+i]=1;        ac.go();        for(int i=0; i<len; i++) ac.init(i,len-1);        ac.dfs(0,0);        puts(ans);    }    return 0;}


0 0
原创粉丝点击