Bootstrap

51nod 1464 半回文(字典树+DFS+预处理)

题目来源:  CodeForces
基准时间限制:1 秒 空间限制:262144 KB 分值: 40  难度:4级算法题
 收藏
 关注

一个字符串t是半回文的条件是,对于所有的奇数 i(1i|t|+12)ti = t|t|  i + 1  始终成立,|t|表示字符串t的长度。下标从1开始。例如"abaa", "a", "bb", "abbbaa"都是半回文,而"ab", "bba"和"aaabaa"则不是。

现在有一个字符串s,只由小写字母a,b构成,还有一个数字k。现在要求找出s的半回文子串中字典序排在第k位的串,字符串可以是一样,只要所在的位置不同就是不一样的串。

样例解释:

这个样例中半回文子串是 a, a, a, a, aa, aba, abaa, abba, abbabaa, b, b, b, b, baab,bab, bb, bbab, bbabaab (按照字典序排序).


Input
单组测试数据。
第一行有一个字符串s(1 ≤ |s| ≤ 5000),只包含'a' 和 'b',|s|表示s的长度。
第二行有一个正整数k。k不超过s子串中是半回文串的总数目。
Output
输出排在第k位的半回文子串。
Input示例
abbabaab
7
Output示例
abaa
System Message  (题目提供者)
Visual C++的运行时限为:1000 ms ,空间限制为:262144 KB  示例及语言说明请按这里

 允许其他 AC 的用户查看此代码,分享代码才能查看别人的代码并有机会获得勋章


题解:假如暴力找出所有子串并判断是否为半回文串,然后按照字典序排序的话是活在梦里,

然而怎么避免活在梦里呢,我们可以考虑字典树,将所有的回文子串加入字典树然后查询。

这样的话避免了排序的复杂度,但是还是够呛,还能怎么优化呢。对于每一个子串,我们可以

通过预处理找到所有合法的子串,并开一个vis数组表示当前位置能延伸到的最远的位置所能构成的

合法子串,这样的话时间复杂度便大大降低了。。。然后dfs找就好了。。(记得要按顺序)

#include<set>  
#include<map>         
#include<stack>                
#include<queue>  
#include<vector>        
#include<string>      
#include<math.h> 
#include<time.h>  
#include<stdio.h>                
#include<iostream>                
#include<string.h>                
#include<stdlib.h>        
#include<algorithm>       
#include<functional>        
using namespace std;
typedef long long ll;
#define inf 1000000000           
#define mod 1000000007                 
#define maxn  6005    
#define PI 3.1415926  
#define lowbit(x) (x&-x)     
#define eps 1e-9
char s[maxn * 1000];
string ans;
int dp[maxn][maxn], k, vis[maxn];
int siz, a[maxn * 1000][2], cnt[maxn * 1000][2];
void insert(int st)   
{
	int i, now = 0, len = strlen(s);
	for (i = st;i <= vis[st];i++)
	{
		int v = s[i] - 'a';
		if (a[now][v] == 0)
			a[now][v] = ++siz;
		if (dp[st][i])
			cnt[now][v]++;
		now = a[now][v];
	}
}
void dfs(int x)
{
	string tmp = ans;
	if (k > 0 && a[x][0])
	{
		k -= cnt[x][0];
		ans = ans + 'a';
		dfs(a[x][0]);
	}
	if (k > 0 && a[x][1])
	{
		ans = tmp;
		k -= cnt[x][1];
		ans = ans + 'b';
		dfs(a[x][1]);
	}
}
int main(void)
{
	int i, j;
	scanf("%s", s);
	scanf("%d", &k);
	int len = strlen(s);
	for (i = len-1;i >= 0;i--)
	{
		dp[i][i] = 1;
		vis[i] = i;
		for (j = i + 1;j < len;j++)
		{
			if (s[i] == s[j])
			{
				if (i + 2 >= j - 2)
					dp[i][j] = 1;
				else
					dp[i][j] = dp[i + 2][j - 2];
			}
			if (dp[i][j])
				vis[i] = j;
		}
	}
	for (i = 0;i < len;i++)
		insert(i);
	dfs(0);
	cout << ans << endl;
	return 0;
}



悦读

道可道,非常道;名可名,非常名。 无名,天地之始,有名,万物之母。 故常无欲,以观其妙,常有欲,以观其徼。 此两者,同出而异名,同谓之玄,玄之又玄,众妙之门。

;