您的位置:首页 > 其它

【HackerRank】Functional Palindromes(回文树+后缀数组+lcp排序+字符串哈希+二分)

2016-08-29 18:59 357 查看
【HackerRank】Functional Palindromes(回文树+后缀数组+lcp排序+字符串哈希+二分)

这个页面抓不太好,大家点进去看吧~~

做过的用到数据结构+算法最多的一个题……真真是做ACM以来做的最最麻烦的一个题……

说白了其实就是板子大杂烩……但是会吐的那种。。

此外……此题价值75$……不要问我为什么。。。TOT

现在进入正片——

给你一个长n的字符串,仅由小写字母组成。然后q次询问。

每次询问该串的所有回文子串里,按字典序从小到大后第k个的回文串。输出它的f函数值。注意回文串不去重。

具体要做的就是,预处理母串的所有回文串,按字典序排序,然后快速找到第k个,输出对应f值。

分为如下子问题:

1·预处理母串所有回文子串——回文树,具体百度,然后与回文树恶战一场吧……!¥@#¥。然后可以把本质不同的回文子串以及对应的出现次数存起来,然后排序。存回文子串可以存该种回文子串出现的左右下标——用以排序。

2·把回文子串按字典序排序——预处理母串的后缀数组,然后可以搞RMQ,弄出来个快速lcp。这样对于上一步存起来的本质不同的回文子串左右下标,通过比较lcp,可以达到快速按字典序排序。

3·快速找到第k个——二分,预处理到某个串所需要的k的下界,这样可以快速二分出第k个串。

4·f函数——字符串哈希,一套板子生砸上……

然后就出来了……GG。。。

因为是边学边造轮子,所以代码比较丑陋……

代码如下:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <vector>
#include <queue>
#include <algorithm>
#define LL long long
#define Pr pair<int,int>

using namespace std;
const int INF = 0x3f3f3f3f;
const int mod = 1e9+7;

const int MAXN = 112345;
int t1[MAXN],t2[MAXN],c[MAXN];

bool cp(int *r,int a,int b,int l)
{
return r[a] == r[b] && r[a+l] == r[b+l];
}

void da(char *str,int *sa,int *rk,int *height,int n,int m)
{
n++;
int i,j,p,*x = t1,*y = t2;
for(i = 0; i < m; ++i) c[i] = 0;
for(i = 0; i < n; ++i) c[x[i] = str[i]]++;
for(i = 1; i < m; ++i) c[i] += c[i-1];
for(i = n-1; i >= 0; --i) sa[--c[x[i]]] = i;
for(j = 1; j <= n; j <<= 1)
{
p = 0;

for(i = n-j; i < n; ++i) y[p++] = i;
for(i = 0; i < n; ++i) if(sa[i] >= j) y[p++] = sa[i]-j;

for(i = 0; i < m; ++i) c[i] = 0;
for(i = 0; i < n; ++i) c[x[y[i]]]++;
for(i = 1; i < m; ++i) c[i] += c[i-1];
for(i = n-1; i >= 0; --i) sa[--c[x[y[i]]]] = y[i];

swap(x,y);
p = 1;
x[sa[0]] = 0;

for(i = 1; i < n; ++i)
x[sa[i]] = cp(y,sa[i-1],sa[i],j)? p-1: p++;
if(p >= n) break;
m = p;
}
int k = 0;
n--;
for(i = 0; i <= n; ++i) rk[sa[i]] = i;
for(i = 0; i < n; ++i)
{
if(k) k--;
j = sa[rk[i]-1];
while(str[i+k] == str[j+k]) k++;
height[rk[i]] = k;
}
}

int rk[MAXN],height[MAXN];
int RMQ[MAXN];
int mm[MAXN];
int best[20][MAXN];

void initRMQ(int n)
{
mm[0] = -1;
for(int i = 1; i <= n; ++i)
mm[i] = ((i&(i-1)) == 0)? mm[i-1]+1: mm[i-1];
for(int i = 1; i <= n; ++i) best[0][i] = i;
for(int i = 1; i <= mm
; i++)
for(int j = 1; j +(1<<i)-1 <= n; j++)
{
int a = best[i-1][j];
int b = best[i-1][j+(1<<(i-1))];
if(RMQ[a] < RMQ[b]) best[i][j] = a;
else best[i][j] = b;
}
}

int askRMQ(int a,int b)
{
int t;
t = mm[b-a+1];
b -= (1<<t)-1;
a = best[t][a];
b = best[t][b];
return RMQ[a] < RMQ[b]? a: b;
}

int lcp(int a,int b,int len)
{
if(a == b) return len-a;
a = rk[a];
b = rk[b];
if(a > b) swap(a,b);
return height[askRMQ(a+1,b)];
}

struct node {
int next[26];
int len;
int sufflink;
int num,l,r;
};

char s[112345];
node tree[MAXN];
int num;            // node 1 - root with len -1, node 2 - root with len 0
int suff;           // max suffix palindrome

bool addLetter(int pos) {
int cur = suff, curlen = 0;
int let = s[pos] - 'a';

while (true) {
curlen = tree[cur].len;
if (pos - 1 - curlen >= 0 && s[pos - 1 - curlen] == s[pos])
break;
cur = tree[cur].sufflink;
}
if (tree[cur].next[let]) {
suff = tree[cur].next[let];
tree[suff].num++;
return false;
}

num++;
suff = num;
tree[num].len = tree[cur].len + 2;
tree[num].r = pos;
tree[num].l = pos-tree[num].len+1;
tree[cur].next[let] = num;

if (tree[num].len == 1) {
tree[num].sufflink = 2;
tree[num].num = 1;
return true;
}

tree[num].num++;
while (true) {
cur = tree[cur].sufflink;
curlen = tree[cur].len;
if (pos - 1 - curlen >= 0 && s[pos - 1 - curlen] == s[pos]) {
tree[num].sufflink = tree[cur].next[let];
break;
}
}
return true;
}

void initTree() {
num = 2; suff = 2;
tree[1].len = -1; tree[1].sufflink = 1;
tree[2].len = 0; tree[2].sufflink = 1;
}

int len;
int r[MAXN];
int sa[MAXN];
vector <int> adj[MAXN];
vector <pair<Pr,int> > vc;

void dfs(int u)
{
for(int i = 0; i < adj[u].size(); ++i)
{
dfs(adj[u][i]);
tree[u].num += tree[adj[u][i]].num;
}
}

bool cmp(pair<Pr,int> a,pair<Pr,int> b)
{
int l1,l2,r1,r2,len1,len2;
l1 = a.first.first;
l2 = b.first.first;
r1 = a.first.second;
r2 = b.first.second;
len1 = r1-l1+1;
len2 = r2-l2+1;

int cp = lcp(l1,l2,len);

if(cp >= len1 || cp >= len2) return len1 <= len2;
else return s[l1+cp] <= s[l2+cp];
}

int P[MAXN],HashF[MAXN],HashR[MAXN];
class RollingHash {
public:
RollingHash() {
prime = 100001;
mod1 = 1000000007;
mod2 = 1897266401;
P[0] = 1;
for(int i=1; i<MAXN; i++) {
P[i] = 1LL * P[i-1] * prime % mod1;
}
}

void Construct() {
HashF[0] = HashR[ len+1 ] = 0;
for(int i=1; i<=len; i++) {
HashF[i] = ( 1LL * HashF[i-1] * prime + s[i-1] ) % mod1;
HashR[len-i+1] = ( 1LL * HashR[len-i+2] * prime + s[ len - i ] ) % mod1;
}
}

int GetForwardHash( int l, int r ) {
if( l == 1 ) return HashF[r];
int hash = HashF[r] - 1LL * HashF[l-1] * P[ r - l + 1 ] % mod1;
if( hash < 0 ) hash += mod1;
return hash;
}
int GetBackwardHash( int l, int r ) {
if( r == len ) return HashR[l];
int hash = HashR[l] - 1LL * HashR[r+1] * P[ r - l + 1 ] % mod1;
if( hash < 0 ) hash += mod1;
return hash;
}
bool IsPalin( int l, int r ) {
if( r < l ) return true;
return (GetForwardHash(l, r) == GetBackwardHash(l, r));
}

private:
int prime, mod1, mod2;
};

vector <pair<LL,int> > by;
LL ans[MAXN];
LL cnt;

void init()
{
da(s,sa,rk,height,len,128);
for(int i = 1; i <= len; ++i) RMQ[i] = height[i];
initRMQ(len);
initTree();
for (int i = 0; i < len; i++)
addLetter(i);

for(int i = 2; i <= num; ++i)
adj[tree[i].sufflink].push_back(i);

dfs(1);

for(int i = 3; i <= num; ++i)
vc.push_back(pair<Pr,int> (Pr(tree[i].l,tree[i].r),tree[i].num));

sort(vc.begin(),vc.end(),cmp);

RollingHash obj;
obj.Construct();

cnt = 1;
for(int i = 0; i < vc.size(); ++i)
{
by.push_back(pair<LL,int> (cnt,i));
ans[i] = obj.GetForwardHash(vc[i].first.first+1,vc[i].first.second+1);
//printf("%d %d %lld\n",vc[i].first.first+1,vc[i].first.second+1,ans[i]);
cnt += vc[i].second;
}

}

int main()
{
int q;
LL k;

scanf("%d%d",&len,&q);
scanf("%s",s);

init();

int pos;

while(q--)
{
scanf("%lld",&k);
if(k >= cnt) puts("-1");
else
{
pos = -1;

int l = 0,r = by.size()-1;

while(l <= r)
{
int mid = (l+r)>>1;
if(k >= by[mid].first)
{
pos = mid;
l = mid+1;
}
else r = mid-1;
}

printf("%lld\n",ans[by[pos].second]);
}
}

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