您的位置:首页 > 其它

HDU 4622 Reincarnation 后缀数组 或 后缀自动机

2015-04-16 19:58 316 查看
题目大意:

就是现在给定字符串S (长度不超过2000), 接下来是Q次询问(Q <= 10000), 每次询问给出 l, r, 输出S[l, r]这一段S的子串中不同字串的个数

大致思路:

首先如果用后缀数组的话不难想到求出S的后缀数组之后, 对于每一次询问 l, r, 遍历height数组找到 l <= sa[i] <= r的那些, 然后用lcp记录之前已经有计算过的长度, 向后遍历的同时更新lcp, 如果某个sa[i]在[l, r]中, 其对答案的贡献是 r - sa[i] + 1 - lcp (如果> 0)

这样复杂度是O(Q|S|)

如果用后缀自动机来做的话我刚开始想的是对于S建立后缀自动机之后, 对于每次询问, 将子串[l, r]在S的后缀自动机上遍历一遍, 统计出现的子串数量, 复杂度最坏情况下O(Q|S|)

后来发现可以对于S的每个后缀建立一次后缀自动机, 预处理出所有 [l, r]之间的子串数量然后O(1)查询, 复杂度O(|S|*|S| + Q)

3种做法的代码如下:

后缀数组做法:

Result  :  Accepted     Memory  :  1696 KB     Time  :  1107 ms

/*
* Author: Gatevin
* Created Time: 2015/4/16 16:01:32
* File Name: Rin_Tohsaka.cpp
*/
#include<iostream>
#include<sstream>
#include<fstream>
#include<vector>
#include<list>
#include<deque>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cmath>
#include<ctime>
#include<iomanip>
using namespace std;
const double eps(1e-8);
typedef long long lint;
#define foreach(e, x) for(__typeof(x.begin()) e = x.begin(); e != x.end(); ++e)
#define SHOW_MEMORY(x) cout<<sizeof(x)/(1024*1024.)<<"MB"<<endl

#define maxn 2333
#define rank Rank
int wa[maxn], wb[maxn], wv[maxn], Ws[maxn];

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

void da(int *r, int *sa, int n, int m)
{
int *x = wa, *y = wb, *t, i, j, p;
for(i = 0; i < m; i++) Ws[i] = 0;
for(i = 0; i < n; i++) Ws[x[i] = r[i]]++;
for(i = 1; i < m; i++) Ws[i] += Ws[i - 1];
for(i = n - 1; i >= 0; i--) sa[--Ws[x[i]]] = i;
for(j = 1, p = 1; p < n; j <<= 1, m = p)
{
for(p = 0, 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 < n; i++) wv[i] = x[y[i]];
for(i = 0; i < m; i++) Ws[i] = 0;
for(i = 0; i < n; i++) Ws[wv[i]]++;
for(i = 1; i < m; i++) Ws[i] += Ws[i - 1];
for(i = n - 1; i >= 0; i--) sa[--Ws[wv[i]]] = y[i];
for(t = x, x = y, y = t, p = 1, x[sa[0]] = 0, i = 1; i < n; i++)
x[sa[i]] = cmp(y, sa[i - 1], sa[i], j) ? p - 1 : p++;
}
return;
}

int rank[maxn], height[maxn];
void calheight(int *r, int *sa, int n)
{
int i, j, k = 0;
for(i = 1; i <= n; i++) rank[sa[i]] = i;
for(i = 0; i < n; height[rank[i++]] = k)
for(k ? k-- : 0, j = sa[rank[i] - 1]; r[i + k] == r[j + k]; k++);
return;
}

char in[maxn];
int s[maxn], sa[maxn];

int solve(int l, int r, int N)
{
lint ans = 0;
int lcp = 0;
for(int i = 1; i <= N; i++)
{
lcp = min(lcp, height[i]);
if(sa[i] >= l && sa[i] <= r)
{
if(r - sa[i] + 1 > lcp)
{
ans += (r - sa[i] + 1 - lcp);
lcp = r - sa[i] + 1;
}
}
}
return ans;
}

int main()
{
int T;
scanf("%d", &T);
while(T--)
{
scanf("%s", in);
int len = strlen(in);
for(int i = 0; i < len; i++)
s[i] = in[i] - 'a' + 1;
s[len] = 0;
da(s, sa, len + 1, 30);
calheight(s, sa, len);
int Q;
scanf("%d", &Q);
while(Q--)
{
int l, r;
scanf("%d %d", &l, &r);
printf("%d\n", solve(l - 1, r - 1, len));
}
}
return 0;
}

后缀自动机的做法:

方式1 O(|S|Q):

Result  :  Accepted     Memory  :  2108 KB     Time  :  2730 ms

/*
* Author: Gatevin
* Created Time: 2015/4/16 16:42:32
* File Name: Rin_Tohsaka.cpp
*/
#include<iostream>
#include<sstream>
#include<fstream>
#include<vector>
#include<list>
#include<deque>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cmath>
#include<ctime>
#include<iomanip>
using namespace std;
const double eps(1e-8);
typedef long long lint;
#define foreach(e, x) for(__typeof(x.begin()) e = x.begin(); e != x.end(); ++e)
#define SHOW_MEMORY(x) cout<<sizeof(x)/(1024*1024.)<<"MB"<<endl

#define maxm 2333
#define maxn 4444
char s[maxm];

struct Suffix_Automation
{
struct State
{
State *par;
State *go[26];
int val, maxcnt;
void init(int _val = 0)
{
par = 0, val = _val;
maxcnt = 0;
memset(go, 0, sizeof(go));
}
};
State *root, *last, *cur;
State nodePool[maxn];
State* newState(int val = 0)
{
cur->init(val);
return cur++;
}
void initSAM()
{
cur = nodePool;
root = newState();
last = root;
}
void extend(int w)
{
State *p = last;
State *np = newState(p->val + 1);
while(p && p->go[w] == 0)
{
p->go[w] = np;
p = p->par;
}
if(p == 0)
np->par = root;
else
{
State *q = p->go[w];
if(p->val + 1 == q->val)
np->par = q;
else
{
State *nq = newState(p->val + 1);
memcpy(nq->go, q->go, sizeof(q->go));
nq->par = q->par;
q->par = nq;
np->par = nq;
while(p && p->go[w] == q)
{
p->go[w] = nq;
p = p->par;
}
}
}
last = np;
}
int d[maxm];
State *b[maxn];
void topo()
{
int maxVal = 0;
int cnt = cur - nodePool;
memset(d, 0, sizeof(d));
for(int i = 1; i < cnt; i++)
maxVal = max(maxVal, nodePool[i].val), d[nodePool[i].val]++;
for(int i = 1; i <= maxVal; i++) d[i] += d[i - 1];
for(int i = 1; i < cnt; i++) b[d[nodePool[i].val]--] = &nodePool[i];
b[0] = root;
}
void solve(int L, int R)
{
for(int i = 0; i < cur - nodePool; i++) b[i]->maxcnt = 0;
State *now = root;
int cnt = 0;
for(int i = L; i <= R; i++)
{
int w = s[i] - 'a';
if(now->go[w])
{
now = now->go[w];
cnt++;
now->maxcnt = max(now->maxcnt, cnt);
}
else
{
while(now && now->go[w] == 0)
{
now = now->par;
if(now)
{
cnt = now->val;
now->maxcnt = cnt;
}
}
if(now == 0)
now = root, cnt = 0;
else
{
now = now->go[w];
cnt++;
now->maxcnt = max(now->maxcnt, cnt);
}
}
}
int ans = 0;
cnt = cur - nodePool;
for(int i = cnt - 1; i > 0; i--)
{
if(b[i]->maxcnt)
{
b[i]->par->maxcnt = b[i]->par->val;
ans += b[i]->maxcnt - b[i]->par->val;
}
}
printf("%d\n", ans);
}
};

Suffix_Automation sam;

int main()
{
int T;
scanf("%d", &T);
while(T--)
{
sam.initSAM();
scanf("%s", s);
int len = strlen(s);
for(int i = 0; i < len; i++)
sam.extend(s[i] - 'a');
sam.topo();
int Q;
scanf("%d", &Q);
while(Q--)
{
int l, r;
scanf("%d %d", &l, &r);
sam.solve(l - 1, r - 1);
}
}
return 0;
}

后缀自动机做法2 O(|S|*|S| + Q):
Result  :  Accepted     Memory  :  15936 KB     Time  :  1357 ms

/*
* Author: Gatevin
* Created Time: 2015/4/16 18:46:12
* File Name: Rin_Tohsaka.cpp
*/
#include<iostream>
#include<sstream>
#include<fstream>
#include<vector>
#include<list>
#include<deque>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cmath>
#include<ctime>
#include<iomanip>
using namespace std;
const double eps(1e-8);
typedef long long lint;
#define foreach(e, x) for(__typeof(x.begin()) e = x.begin(); e != x.end(); ++e)
#define SHOW_MEMORY(x) cout<<sizeof(x)/(1024*1024.)<<"MB"<<endl

#define maxn 4444
#define maxm 2333
char s[maxm];

struct Suffix_Automation
{
struct State
{
State *par;
State *go[26];
int right, val, mi;
void init(int _val = 0)
{
par = 0, val = _val, right = mi = 0;
memset(go, 0, sizeof(go));
}
int calc()
{
if(par == 0) return 0;
else return val - par->val;
}
};
State *root, *cur, *last;
State nodePool[maxn];
int tot;
State* newState(int val = 0)
{
cur->init(val);
return cur++;
}
void initSAM()
{
cur = nodePool;
root = newState();
last = root;
tot = 0;
}
void extend(int w)
{
State *p = last;
State *np = newState(p->val + 1);
np->right = 1;
while(p && p->go[w] == 0)
{
p->go[w] = np;
p = p->par;
}
if(p == 0)
{
np->par = root;
tot += np->calc();
}
else
{
State *q = p->go[w];
if(q->val == p->val + 1)
{
np->par = q;
tot += np->calc();
}
else
{
State *nq = newState(p->val + 1);
memcpy(nq->go, q->go, sizeof(q->go));
tot -= q->calc();
nq->par = q->par;
q->par = nq;
np->par = nq;
tot += q->calc() + nq->calc() + np->calc();
while(p && p->go[w] == q)
{
p->go[w] = nq;
p = p->par;
}
}
}
last = np;
}
int d[maxm];
State *b[maxn];
void topo()
{
int maxVal = 0;
memset(d, 0, sizeof(d));
int cnt = cur - nodePool;
for(int i = 1; i < cnt; i++)
maxVal = max(maxVal, nodePool[i].val), d[nodePool[i].val]++;
for(int i = 1; i <= maxVal; i++) d[i] += d[i - 1];
for(int i = 1; i < cnt; i++) b[d[nodePool[i].val]--] = &nodePool[i];
b[0] = root;
}
void SAMInfo()
{
int cnt = cur - nodePool;
State *p;
for(int i = cnt - 1; i > 0; i--)
{
p->par->right += p->right;
p->mi = p->par->val + 1;
}
}
int ans[2010][2010];
void solve(char *s, int len)
{
for(int i = 0; i < len; i++)
{
initSAM();
for(int j = i; j < len; j++)
{
extend(s[j] - 'a');
ans[i][j] = tot;
}
}
int Q;
scanf("%d", &Q);
while(Q--)
{
int l, r;
scanf("%d %d", &l, &r);
printf("%d\n", ans[l - 1][r - 1]);
}
}
};

Suffix_Automation sam;

int main()
{
int T;
scanf("%d", &T);
while(T--)
{
scanf("%s", s);
int len = strlen(s);
sam.solve(s, len);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息