您的位置:首页 > 其它

Codeforces 557E Ann and Half-Palindrome (字典树+字符串排序)

2015-10-02 02:13 405 查看

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

思路:枚举字符串长度,然后O(n*n)判定所有字符串是否是半回文串,剩下要做的就是给这些字符串排序,如果直接排序,时间复杂度和空间复杂度都无法承受,考虑用trie树,将原串所有后缀插入到trie树中,如果当前枚举的子串是半回文串那么trie树的权值加一,查找时注意找到答案后要要在答案后面的一位置'\0'。 

#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<vector>
#include<map>
#include<queue>
#include<stack>
#include<string>
#include<map>
#include<set>
#include<ctime>
#define eps 1e-6
#define LL long long
#define pii pair<int, int>
//#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;

const int MAXN = 5100;
const int maxnode = 20000000;
const int sigma_size = 2;
int dp[MAXN][MAXN];
int k;
int sumv[MAXN][MAXN];
char str[MAXN], ans[MAXN];;
struct Trie {
int ch[maxnode][sigma_size];
int val[maxnode];
int sz;
Trie() { sz = 1; memset(ch[0], 0, sizeof(ch[0]));};
int idx(char c) {return c - 'a';}
void insert(char *s, int cur) {
int u = 0, n = strlen(s);
for(int i = 0; i < n; i++) {
int c = idx(s[i]);
if(!ch[u][c]) {
memset(ch[sz], 0, sizeof(ch[sz]));
val[sz] = dp[cur][cur+i];
ch[u][c] = sz++;
}
else val[ch[u][c]] += dp[cur][cur+i];
u = ch[u][c];
}
}
void dfs(int cur, int pos) {
if(k>val[cur]) {
k -= val[cur];
for(int i = 0; i < 2; i++) {
if(!ch[cur][i]) continue;
ans[pos] = 'a' + i;
dfs(ch[cur][i], pos+1);
if(k<=0) return;
}
}
else {
k -= val[cur];
ans[pos] = 0;
}
}

} trie;
int main() {
//freopen("input.txt", "r", stdin);
cin >> (str+1);
cin >> k;
int len = strlen((str+1));
for(int i = 1; i <= len; i++) dp[i][i] = 1;
for(int i = 1; i < len; i++) dp[i][i+1] = (str[i]==str[i+1]);
for(int i = 3; i <= len; i++) {
for(int j = 1; j+i-1 <= len; j++) {
dp[j][j+i-1] = ((j+2>j+i-3||dp[j+2][j+i-3]) && str[j]==str[i+j-1]);
}
}
for(int i = 1; i <= len; i++) trie.insert(str+i, i);
trie.dfs(0, 0);
cout << ans << endl;
return 0;
}



 

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  codeforce 前缀树 TRIE