您的位置:首页 > 其它

HDU-2017 ACM/ICPC Asia Regional Shenyang Online-1001-string string string

2017-09-12 16:57 531 查看
ACM模版

描述



题解

后缀自动机……我知识的盲区,学过 AC 自动机,后缀数组,等等算法,就是没有学过这个……怪不得做不出来。

建立后缀自动机后,对每个节点统计出现次数,然后对字符串的后缀进行加一,更新每个节点的父节点就好了。

代码

#include <iostream>
#include <cstring>

using namespace std;

typedef long long ll;

const int MAXN = 2e5 + 10;
const int MAGIC = 26;

class SAM
{
public:
int n;
int last, tot;
char s[MAXN];
int c[MAXN];
int q[MAXN];
int pre[MAXN];
int cnt[MAXN];
int len[MAXN];
int step[MAXN];
int son[MAXN][MAGIC + 1];

void clear(char *_s)
{
n = (int)strlen(_s);
memcpy(s, _s, sizeof(char) * (n + 5));

int t = (n << 1) + 10;
for (int i = 0; i < t; i++)
{
for (int j = 0; j < MAGIC; j++)
{
son[i][j] = 0;
}
pre[i] = step[i] = 0;
}
last = tot = 0;
}

void extend(char ch)
{
step[++tot] = step[last] + 1;
int p = last, np = tot;

for (; !son[p][ch]; p = pre[p])
{
son[p][ch] = np;
}
if (!p)
{
pre[np] = 1;
}
else
{
int q = son[p][ch];
if (step[q] == step[p] + 1)
{
pre[np] = q;
}
else
{
step[++tot] = step[p] + 1;
int nq = tot;
memcpy(son[nq], son[q], sizeof(son[q]));
pre[nq] = pre[q];
pre[q] = pre[np] = nq;
for (; son[p][ch] == q; p = pre[p])
{
son[p][ch] = nq;
}
}
}

last = np;
cnt[last]++;
}

void build()
{
int t = (n << 1) + 10;
for (int i = 0; i < t; i++)
{
cnt[i] = 0;
}
last = tot = 1;
for (int i = 0; i < n; i++)
{
extend(s[i] - 'a');
}
}

void calc(int k)
{
int t = (n << 1) + 10;
for (int i = 0; i < t; i++)
{
c[i] = 0;
}
for (int i = 1; i <= tot; i++)
{
c[step[i]]++;
}
for (int i = 1; i <= tot; i++)
{
c[i] += c[i - 1];
}
for (int i = 1; i <= tot; i++)
{
q[c[step[i]]--] = i;
}

ll ans = 0;
for (int i = tot; i; i--)
{
int u = q[i];
if (pre[u] > 0)
{
cnt[pre[u]]+=cnt[u];
}
if (cnt[u] == k)
{
ans += step[u] - step[pre[u]];
}
}

printf("%lld\n",ans);
}
} S;

int k;
char s[MAXN];

int main()
{
int T;
scanf("%d", &T);

while (T--)
{
scanf("%d%s", &k, s);

S.clear(s);
S.build();
S.calc(k);
}

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