标签:顺序 turn 删掉 一个栈 bool -- out 好的 sam
bzoj 3942: 注意到没有一个串被另一个串完全包含是个很好的性质,如果没有就意味着按顺序匹配的话每匹配到一个就可以直接删掉。
那就维护一个栈来搞当前在哪里,然后直接在ac自动机上匹配即可,匹配掉了就弹掉。
#include <bits/stdc++.h>
#pragma GCC optimize(2)
#define rep(i, l, r) for (int i = (l); i <= (r); ++i)
#define per(i, r, l) for (int i = (r); i >= (l); --i)
using namespace std;
typedef long long ll;
typedef pair <int, int> pii;
typedef vector <int> vi;
int gi() {
int f = 1, x = 0; char ch = getchar();
while (ch < '0' || ch > '9') {if (ch == '-') f = -1; ch = getchar();}
while (ch >= '0' && ch <= '9') {x = x * 10 + ch - '0'; ch = getchar();}
return f * x;
}
const int N = 100005;
int tr[N][26], fail[N], e[N], tot, n, pos[N], tp;
char s[N], t[N], st[N];
void Build(char* s) {
int u = 0;
for (int i = 1; s[i]; ++i) {
if (!tr[u][s[i] - 'a'])
tr[u][s[i] - 'a'] = ++tot;
u = tr[u][s[i] - 'a'];
}
e[u] = strlen(s + 1);
}
void Getfail() {
queue<int> q;
for (int i = 0; i < 26; ++i)
if (tr[0][i])
q.push(tr[0][i]);
while (!q.empty()) {
int u = q.front();
q.pop();
for (int i = 0; i < 26; ++i) {
if (tr[u][i])
fail[tr[u][i]] = tr[fail[u]][i], q.push(tr[u][i]);
else
tr[u][i] = tr[fail[u]][i];
}
}
}
int main() {
scanf("%s", t + 1);
n = gi();
rep (i, 1, n) {
scanf ("%s", s + 1);
Build(s);
}
Getfail();
int m = strlen(t + 1), now = 0;
st[++tp] = ' ';
pos[tp] = now;
rep (i, 1, m) {
now = tr[now][t[i] - 'a'];
pos[++tp] = now;
st[tp] = t[i];
if (e[now]) {
assert(tp >= e[now]);
tp -= e[now];
now = pos[tp];
}
}
rep(i, 2, tp) putchar(st[i]);
return 0;
}
bzoj 4974:
首先用i-per[i]求出fail[i],并钦定第一个字符为a。
如果没跳到头肯定能知道这个字母是啥。如果跳到头了,那就mark一下已经被用过的字符,选一个最小的没被用到的填上。
#include <bits/stdc++.h>
#pragma GCC optimize(2)
#define rep(i, l, r) for (int i = (l); i <= (r); ++i)
#define per(i, r, l) for (int i = (r); i >= (l); --i)
using namespace std;
typedef long long ll;
typedef pair <int, int> pii;
typedef vector <int> vi;
int gi() {
int f = 1, x = 0; char ch = getchar();
while (ch < '0' || ch > '9') {if (ch == '-') f = -1; ch = getchar();}
while (ch >= '0' && ch <= '9') {x = x * 10 + ch - '0'; ch = getchar();}
return f * x;
}
const int N = 1000010;
int n, per[N], fail[N], ans[N];
int main() {
n = gi();
rep (i, 1, n) per[i] = gi(), fail[i] = i - per[i];
ans[1] = 0;
rep (i, 2, n) {
if (fail[i])
ans[i] = ans[fail[i]];
else {
int pos = fail[i - 1];
vi used(26);
while (true) {
used[ans[pos + 1]] = 1;
if (!pos) break;
pos = fail[pos];
}
for (int j = 0; j < 26; ++j) if (!used[j]) {
ans[i] = j;
break;
}
}
}
rep(i, 1, n) putchar(ans[i] + 'a');
return 0;
}
poj2185
先把每行当做一个字符,把列最小周期求出来,再把列当做一个字符,求行的最小周期即可。
#include <bits/stdc++.h>
#pragma GCC optimize(2)
#define rep(i, l, r) for (int i = (l); i <= (r); ++i)
#define per(i, r, l) for (int i = (r); i >= (l); --i)
using namespace std;
typedef long long ll;
typedef pair <int, int> pii;
typedef vector <int> vi;
int gi() {
int f = 1, x = 0; char ch = getchar();
while (ch < '0' || ch > '9') {if (ch == '-') f = -1; ch = getchar();}
while (ch >= '0' && ch <= '9') {x = x * 10 + ch - '0'; ch = getchar();}
return f * x;
}
const int N = 10000 + 5, M = 105;
char s[N][M];
int n, m, fail[N], sn, sm;
bool same(int l, int r) {
rep (i, 1, m) if (s[l][i] != s[r][i]) return 0;
return 1;
}
bool _same(int l, int r) {
rep (i, 1, sn) if (s[i][l] != s[i][r]) return 0;
return 1;
}
int main() {
n = gi(), m = gi();
rep (i, 1, n)
scanf("%s", s[i] + 1);
fail[1] = 0;
for (int i = 2, j = 0; i <= n; ++i) {
while (j && !same(j + 1, i)) j = fail[j];
j += same(j + 1, i);
fail[i] = j;
}
sn = n - fail[n];
fail[1] = 0;
for (int i = 2, j = 0; i <= m; ++i) {
while (j && !_same(j + 1, i)) j = fail[j];
j += _same(j + 1, i);
fail[i] = j;
}
sm = m - fail[m];
cout << sn * sm << endl;
return 0;
}
标签:顺序 turn 删掉 一个栈 bool -- out 好的 sam
原文地址:https://www.cnblogs.com/LiM-817/p/12255325.html