DNA 序列
题目链接:ybtoj高效进阶 21175
题目大意
给你一个由四种字符组成的字符串,然后问你长度为 k 的子串中出现次数最多的串的出现次数。
1<=k<=10
思路
其实因为 1 ⩽ k ⩽ 10 1\leqslant k\leqslant 10 1⩽k⩽10,而且只有四种字符,所以我们可以直接暴力搞。
但我直接用 SAM 了。
(因为用 SAM 也是模板题)
代码
#include<cstdio>
#include<cstring>
#include<iostream>
#define ll long long
using namespace std;
struct node {
int son[4], len, fa;
ll sz;
}d[10000001];
char s[5000001];
int sn, k, lst, tot;
ll ans;
int ck(char c) {
if (c == 'A') return 0;
if (c == 'T') return 1;
if (c == 'G') return 2;
return 3;
}
void insert(int x) {
int p = lst;
int np = ++tot;
lst = np;
d[np].len = d[p].len + 1;
d[np].sz = 1;
for (; p && !d[p].son[x]; p = d[p].fa) d[p].son[x] = np;
if (!p) d[np].fa = 1;
else {
int q = d[p].son[x];
if (d[q].len == d[p].len + 1) d[np].fa = q;
else {
int nq = ++tot;
d[nq] = d[q];
d[nq].sz = 0;
d[nq].len = d[p].len + 1;
d[q].fa = d[np].fa = nq;
for (; p && d[p].son[x] == q; p = d[p].fa) d[p].son[x] = nq;
}
}
}
int tong[5000001], xl[10000001];
void DP() {
for (int i = 1; i <= tot; i++)
tong[d[i].len]++;
for (int i = 1; i <= sn; i++)
tong[i] += tong[i - 1];
for (int i = 1; i <= tot; i++) {
xl[tong[d[i].len]--] = i;
}
for (int i = tot; i >= 1; i--)
d[d[xl[i]].fa].sz += d[xl[i]].sz;
}
int main() {
// freopen("dna.in", "r", stdin);
// freopen("dna.out", "w", stdout);
scanf("%s", s + 1);
sn = strlen(s + 1);
scanf("%d", &k);
lst = tot = 1;
for (int i = 1; i <= sn; i++) {
insert(ck(s[i]));
}
DP();
for (int i = 1; i <= tot; i++) {
if (d[i].len >= k && d[d[i].fa].len + 1 <= k) {
ans = max(ans, d[i].sz);
}
}
printf("%lld", ans);
return 0;
}