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

来源:互联网 发布:淘宝老顾客互换资源 编辑:程序博客网 时间:2024/06/10 16:51
1464 半回文
题目来源: 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示例
abbabaab7
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-9char 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;elsedp[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;}