找出s的子串中字典序第k小的“半回文串” Trie Codeforce Div. 2 Ann and Half-Palindrome

http://codeforces.com/problemset/problem/557/E

题意

找出s的子串中字典序第k小的“半回文串”,给出半回文串定义是:对于任意i<=|s|/2 有s[i] = s[len-i+1]

思路

这用dp推下就可以了,dp[i][j]表从i到j是否是回文串 
则dp[i][j] = dp[i+2][j-2](j-i>=4),其他的都是奇回文串; 
要输出第k个字典序的子串,首先肯定想到要用字典树输出来就是了,很简单的dfs就可以了。插入串的时候,就不要一个一个插了,而直接插一个后缀就可以了这样总的复杂度也就是O(n * n),n是串的长度。

http://codeforces.com/blog/entry/18943

This problem can be solved with help of dynamic programming.

At first we calculate matrix good[][]. In good[i][j] we put true, if substring from position i to position j half-palindrome. Else we put ingood[i][j]false. We can do it with iterating on "middle" of half-palindrome and expanding it to the left and to the right. There are 4 cases of "middle" but we omit it because they are simple enough.

Now we need to use Trie and we will put in it suffixes of given string. Also we will store array cnt[]. In cnt[v] we will store number of half-palindromes which ends in vertex v of our Trie. Let now we put in tree suffix which starts in position i, current symbol of string which we put is in position j and we go in vertex v of out Trie. Then if good[i][j] = true we add one to cnt[v].

Now with help of dfs let calculate for every vertex sum[v] — sum of numbers which stored in array cnt[] for vertex v and for vertices in all subtrees of vertex v.

It is left only to restore answer. Start from root of our Trie. We will store answer in variable ans. In variable k store number of required substring. Let now we in vertex v, by letter 'a' we can go in vertex toa and by letter 'b' — in vertex tob.

Then if sum[toa] ≤ k we make ans +  = 'a' and go in vertex toa of our Trie. Else we need to make as follows: k —  = sum[toa],ans +  = 'b' and go in vertex tob of our Trie.

When k will be  ≤ 0 print resulting string ans and finish algorithm.

Asymptotic behavior of this solution — O(szalph * n2) where szalph — size of input alphabet (in this problem it equals to two) and n — length of given string.

http://codeforces.com/contest/557/submission/13470601

#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>

#define For(i,x,y) for (int i=x;i<y;i++)
#define Pb push_back
using namespace std;

const int N=5000+19,Top=20000000;
int f[N][N],n,k;
char s[N];
string Ans;

int DP(int L,int R)
{
	if (~f[L][R]) return f[L][R];
	return f[L][R]=L>=R?1:(s[L]==s[R]&&DP(L+2,R-2));
}

//Trie
int son[Top][2],cnt[Top],Sum[Top],tot,x,t,y;

void DFS(int x)
{
	Sum[x]=cnt[x];
	For(i,0,2) if (int y=son[x][i]) DFS(y),Sum[x]+=Sum[y];
}
void DFS_2(int x)
{
	if (k<=cnt[x]) return;k-=cnt[x];
	For(i,0,2)
		if (int y=son[x][i])
			if (k>Sum[y]) k-=Sum[y];else {Ans.Pb(i+'a'),DFS_2(y);break;}
}

int main()
{
	memset(f,-1,sizeof(f));
	scanf("%s%d",s,&k);n=strlen(s);
	For(i,0,n) For(j,i,n) f[i][j]=DP(i,j);
	For(i,0,n)
	{
		x=0;
		For(j,i,n)
		{
			int &u=son[x][s[j]-'a'];
			if (!u) u=++tot;x=u;
			if (f[i][j]) cnt[x]++;
		}
	}
	DFS(0);
	DFS_2(0);
	puts(Ans.c_str());
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值