题意:
给一个长度为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 20000007 char 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; }
版权声明:本文为博主原创文章,未经博主允许不得转载。
时间: 2024-11-06 07:28:51