cf #311 E. Ann and Half-Palindrome (dp+字典树)

题目:http://codeforces.com/contest/557/problem/E

题意:定义半回文串:字符串前面一半的奇数位上的字符和后一边对应位置上的字符相同的字符串。给定长度|s|<=5000的字符串,求它的半回文子串中,字典序第K小的半回文子串。

分析:定义dp[i][j]表示区间[i,j]代表的子串是否为半回文串。然后n^2推出所有的半回文子串。将所有的半回文子串插入字典树,然后遍历一下字典树,找到正确的位置输出就行了。

代码:

#include <bits/stdc++.h>
using namespace std;

typedef long long LL;
typedef unsigned long long ULL;
const LL INF = 1E9+9;
const int maxn = 5555;
char s[maxn];
int n,k;
bool dp[maxn][maxn],hasFind;

int trie[maxn*maxn][2],cnt,root,cover[maxn*maxn],fa[maxn*maxn];

int newnode()
{
	trie[cnt][0]=trie[cnt][1]=-1;
	cover[cnt]=0;
	return cnt++;
}
void Init()
{
	cnt=0;
	root=newnode();
}
void Insert(int start)
{
	int cur=root;
	for(int i=start;i<n;i++)
	{
		int index=s[i]-'a';
		if(trie[cur][index]==-1)
			trie[cur][index]=newnode();
		fa[trie[cur][index]]=cur;
		cur=trie[cur][index];
		if(dp[start][i])
			cover[cur]++;
	}
}
void dfs(int cur)
{
	if(hasFind)
		return ; 
	k-=cover[cur];
	if(k<=0)
	{
		hasFind=true;
		int f=0;
		while(cur)
		{
			s[f++]=(trie[fa[cur]][0]==cur?'a':'b');
			cur=fa[cur];
		}
		for(int i=f-1;i>=0;i--)
			putchar(s[i]);
		return ;
	}
	for(int i=0;i<2;i++)
		if(trie[cur][i]!=-1)
			dfs(trie[cur][i]);
}

int main()
{
	scanf("%s%d",s,&k);
	n=strlen(s); 
	for(int i=n-1;i>=0;i--)
		for(int j=i;j<n;j++)
			dp[i][j]=(j-i<=4?(s[i]==s[j]):((s[i]==s[j])&&dp[i+2][j-2]));
	Init();
	for(int i=0;i<n;i++)
		Insert(i);
	dfs(root);
	return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值