颓废again
[POI2938]病毒
AC自动机好题,正解挺套路的。在AC自动机上建立Trie图。如果不是危险节点的字母能连成一条环。那么就有无限长的安全代码。
AC代码:
#include <iostream>
#include <cstdio>
#include <queue>
#include <cstring>
const int MAXN = 100000;
const int CHA = 2;
using namespace std;
inline int read() {
int x = 0, w = 1; char c = ' ';
while (c < '0' || c > '9') {
c = getchar(); if (c == '-') w = -1;
}
while (c >= '0' && c <= '9')
x = (x << 1) + (x << 3) + (c ^ 48), c = getchar();
return x * w;
}
char P[MAXN + 5];
bool f = true;
class AcAutomaton {
public :
AcAutomaton() {}
void insert(char *P);
void GetFail();
void dfs(int u);
private :
queue < int > Q;
int tot, fail[MAXN + 5], Trie[MAXN + 5][CHA];
bool val[MAXN + 5], vis[MAXN + 5], InSta[MAXN + 5];
}AC;
void AcAutomaton::insert(char *P) {
int now = 0, L = strlen(P);
for (int i = 0; i < L; ++i) {
int c = P[i] - '0';
if (!Trie[now][c]) Trie[now][c] = ++tot;
now = Trie[now][c];
}
val[now] = true;
}
void AcAutomaton::GetFail() {
for (int i = 0; i < CHA; ++i) {
int u = Trie[0][i];
if (u) fail[u] = 0, Q.push(u);
}
while (!Q.empty()) {
int cur = Q.front(); Q.pop();
for (int i = 0; i < CHA; ++i) {
int u = Trie[cur][i];
if (u)
fail[u] = Trie[fail[cur]][i], val[u] |= val[fail[u]], Q.push(u);
else
Trie[cur][i] = Trie[fail[cur]][i];
}
}
}
void AcAutomaton::dfs(int u) {
if (!f) return;
InSta[u] = true, vis[u] = true;
for (int i = 0; i < CHA; ++i) {
int v = Trie[u][i];
if (InSta[v]) {
f = false; return;
}
else if (!vis[v] && !val[v])
dfs(v);
}
InSta[u] = false;
}
int main() {
int n = read();
for (int i = 1; i <= n; ++i)
scanf("%s", P), AC.insert(P);
AC.GetFail();
AC.dfs(0);
if (f) puts("NIE"); else puts("TAK");
return 0;
}
最大流
省选时候考了最大流。大家都说是套路题,然而我看不出来。
所以我又重新学习了一遍最大流的Dinic算法(原来只会递归版Isap)。
加了一些玄学优化,在LOJ上跑得比Isap快几十倍,不知道怎么回事。
AC代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#define min(a, b) (a < b ? a : b)
typedef long long LL;
const int MAXN = 100000;
const int INF = 0x3f3f3f3f;
using namespace std;
inline int read() {
int x = 0, w = 1; char c = ' ';
while (c < '0' || c > '9') {
c = getchar(); if (c == '-') w = -1;
}
while (c >= '0' && c <= '9')
x = (x << 1) + (x << 3) + (c ^ 48), c = getchar();
return x * w;
}
struct Node {
int to, w, nxt;
};
class Graph {
public:
Graph() {tot = 0, memset(head, -1, sizeof(head));}
void add(int u, int v, int w) {
edge[tot] = (Node) {v, w, head[u]}, head[u] = tot++;
edge[tot] = (Node) {u, 0, head[v]}, head[v] = tot++;
}
bool bfs(int s, int t); int dfs(int u, int t, int flow);
LL Dinic(int s, int t);
private:
Node edge[MAXN * 2 + 5];
int tot, level[MAXN + 5], head[MAXN + 5], cur[MAXN + 5];
queue < int > Q;
}G;
bool Graph::bfs(int s, int t) {
memset(level, 0, sizeof(level));
while (!Q.empty()) Q.pop();
Q.push(s), level[s] = 1;
while (!Q.empty()) {
int u = Q.front(); Q.pop();
for (int i = head[u]; ~i; i = edge[i].nxt) {
int v = edge[i].to, cap = edge[i].w;
if (cap && !level[v]) {
Q.push(v);
level[v] = level[u] + 1;
if (v == t) return true;
}
}
}
return level[t];
}
int Graph::dfs(int u, int t, int flow) {
if (u == t || !flow) return flow;
int used = 0;
for (int &i = cur[u]; ~i && used < flow; i = edge[i].nxt) {
int v = edge[i].to, &cap = edge[i].w, &rcap = edge[i ^ 1].w;
if (cap && level[u] + 1 == level[v]) {
int d = dfs(v, t, min(cap, flow - used));
if (d) {
cap -= d, rcap += d;
used += d;
return d;
}
else
level[v] = -INF;
}
}
return 0;
}
LL Graph::Dinic(int s, int t) {
LL MaxFlow = 0;
while (bfs(s, t)) {
memcpy(cur, head, sizeof(head));
while (int f = dfs(s, t, INF)) MaxFlow += f;
}
return MaxFlow;
}
int main() {
int n = read(), m = read(), s = read(), t = read();
for (int i = 1; i <= m; ++i) {
int u = read(), v = read(), w = read();
G.add(u, v, w);
}
printf("%d\n", G.Dinic(s, t));
return 0;
}