AC自动机匹配
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+5;
int n,tot,tr[N][26],fail[N],cnt[N];
char s[N];
inline void add(){
int len=strlen(s+1),p=0,c;
for(int i=1;i<=len;i++){
c=s[i]-'a';
if(!tr[p][c]) tr[p][c]=++tot;
p=tr[p][c];
}
cnt[p]++;
}
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 x=q.front();
q.pop();
for(int i=0;i<26;i++)
if(tr[x][i])
fail[tr[x][i]]=tr[fail[x]][i],q.push(tr[x][i]);
else tr[x][i]=tr[fail[x]][i];
}
}
inline int query(){
int len=strlen(s+1),p=0,c,res=0;
for(int i=1;i<=len;i++){
c=s[i]-'a';
p=tr[p][c];
for(int j=p;j&&cnt[j]!=-1;j=fail[j])
res+=cnt[j],cnt[j]=-1;
}
return res;
}
int main(){
ios::sync_with_stdio(0);
cin>>n;
for(int i=1;i<=n;i++){
cin>>(s+1);
add();
}
getfail();
cin>>(s+1);
cout<<query();
return 0;
}
后缀自动机(模板)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e6+5;
int n,tot=1,las=1;
ll ans;
char s[N];
struct Node{
int ch[26],len,fa;
}t[N<<1];
inline void add(int c){
int p=las,np=las=++tot;
t[np].len=t[p].len+1;
for(;p&&!t[p].ch[c];p=t[p].fa) t[p].ch[c]=np;
if(!p) t[np].fa=1;
else{
int q=t[p].ch[c];
if(t[q].len==t[p].len+1) t[np].fa=q;
else{
int nq=++tot;
t[nq]=t[q];
t[nq].len=t[p].len+1;
t[np].fa=t[q].fa=nq;
for(;p&&t[p].ch[c]==q;p=t[p].fa) t[p].ch[c]=nq;
}
}
}
int main(){
ios::sync_with_stdio(0);
cin>>(s+1);
n=strlen(s+1);
for(int i=1;i<=n;i++) add(s[i]-'a');
return 0;
}
马拉车算法
#include<bits/stdc++.h>
using namespace std;
const int N=2.2e7+50;
int n,p[N],len,ans;
char s[N],ps[N];
int main(){
ios::sync_with_stdio(0);
cin>>(ps+1);
n=strlen(ps+1);
s[++len]='~';
s[++len]='#';
for(int i=1;i<=n;i++){
s[++len]=ps[i];
s[++len]='#';
}
s[++len]='&';
for(int i=1,mid=0,r=0;i<=len;i++){
if(i<=r) p[i]=min(r-i+1,p[2*mid-i]);
while(s[i-p[i]]==s[i+p[i]]) p[i]++;
if(i+p[i]>r) r=i+p[i]-1,mid=i;
}
for(int i=1;i<=len;i++) ans=max(ans,p[i]);
cout<<ans-1;
return 0;
}
后缀数组(O(nlogn))
#include<bits/stdc++.h>
#define rk x
using namespace std;
const int N=1e6+2;
int n,m,x[N],y[N],sa[N],c[N],ht[N];
//x[i]:起始位置为i的后缀的排名
//y[i]:排名为i的第二关键字所对应的第一关键字的位置
//sa[i]:排名为i的后缀的开始位置
//c[i]:桶
char s[N];
void getsa(){
for(int i=1;i<=n;i++){
x[i]=s[i];
c[x[i]]++;
}
//第一关键字桶排序
for(int i=2;i<=m;i++) c[i]+=c[i-1];
//给桶做前缀和
for(int i=n;i>=1;i--) sa[c[x[i]]--]=i;
//计算sa数组,值相同,先扫到的点排名大
for(int k=1;k<=n;k<<=1){
//倍增计算,每次把两个长度为k的区间合并
int p=0;
//一个指针
for(int i=n-k+1;i<=n;i++) y[++p]=i;
//最后的n-k+1个点没有第二关键字,把排名设成最靠前
for(int i=1;i<=n;i++)
if(sa[i]>k) y[++p]=sa[i]-k;
//最前面的k个点没有对应的第一关键字
for(int i=1;i<=m;i++) c[i]=0;
for(int i=1;i<=n;i++) c[x[i]]++;
for(int i=2;i<=m;i++) c[i]+=c[i-1];
//重置桶
for(int i=n;i>=1;i--){
sa[c[x[y[i]]]--]=y[i];
y[i]=0;
}
//对第一关键字排序,值相同,先扫到(y排名大)的排名大
swap(x,y);
p=1,x[sa[1]]=1;
//排名为1的后缀的排名是1
for(int i=2;i<=n;i++){
if(y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k]) x[sa[i]]=p;
//如果两个后缀第一、第二关键字都相同,说明是同一个串
else x[sa[i]]=++p;
}
if(p==n) break;
//没有重复的数字,已经排完了
m=p;
}
}
void getht(){
int k=0;
//记H[i]=ht[rk[i]],由H[i]>=H[i-1]-1动态维护H数组
//rk数组与sa数组互为反函数:
//sa[i]:排名为i的后缀的起始位置
//rk[i]:起始位置为i的后缀的排名
for(int i=1;i<=n;i++){
if(rk[i]==1) continue;
//H[1]=ht[rk[i]]=0
if(k) k--;
//H[i]>=H[i-1]-1
int j=sa[rk[i]-1];
//j是[[[按照字典序]排在i后缀前面的]后缀的]起始位置
while(i+k<=n&&j+k<=n&&s[i+k]==s[j+k]) k++;
//从i和j两个后缀的第k(H[i-1])一位一位暴力向后匹配
ht[rk[i]]=k;
//H[i]=ht[rk[i]]
}
}
有源汇有上下界最大流
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=210,M=3e5+1;
const ll inf=(1ll<<60);
int n,m,tot=1,head[N],now[N],dis[N];
ll in[N],out[N];
struct Node{
int ver,nxt;
ll flow;
}e[M];
template <typename T>
inline void read(T &x){
x=0;
int f=1;
char ch=getchar();
while(!isdigit(ch)){
if(ch=='-') f=-1;
ch=getchar();
}
while(isdigit(ch)){
x=x*10+(ch-'0');
ch=getchar();
}
x*=f;
}
inline void add(int x,int y,ll f){
tot++;
e[tot].ver=y;
e[tot].nxt=head[x];
e[tot].flow=f;
head[x]=tot;
}
inline bool bfs(int st,int ed){
memset(dis,0,sizeof dis);
queue<int> q;
q.push(st);
dis[st]=1,now[st]=head[st];
while(!q.empty()){
int x=q.front();
q.pop();
for(int i=head[x];i;i=e[i].nxt){
int y=e[i].ver;
ll f=e[i].flow;
if(f&&!dis[y]){
dis[y]=dis[x]+1;
now[y]=head[y];
if(y==ed) return true;
q.push(y);
}
}
}
return false;
}
inline ll dfs(int x,int ed,ll minf){
if(x==ed) return minf;
ll res=0;
for(int i=now[x];i&&minf;i=e[i].nxt){
int y=e[i].ver;
ll f=e[i].flow;
now[x]=i;
if(f&&dis[y]==dis[x]+1){
ll k=dfs(y,ed,min(minf,f));
if(!k) dis[y]=0;
res+=k,minf-=k;
e[i].flow-=k;
e[i^1].flow+=k;
}
}
return res;
}
inline ll dinner(int st,int ed){
ll sum=0;
while(bfs(st,ed)) sum+=dfs(st,ed,inf);
return sum;
}
int main(){
int S,T,st,ed;
read(n),read(m),read(st),read(ed);
for(int i=1,x,y,l,r;i<=m;i++){
read(x),read(y),read(l),read(r);
add(x,y,r-l);
add(y,x,0);
out[x]+=l;
in[y]+=l;
}
S=n+1,T=n+2;
add(ed,st,inf);
add(st,ed,0);
for(int i=1;i<=n;i++){
if(in[i]>out[i]){
out[S]+=in[i]-out[i];
add(S,i,in[i]-out[i]);
add(i,S,0);
}
if(in[i]<out[i]){
add(i,T,out[i]-in[i]);
add(T,i,0);
}
}
ll sum=dinner(S,T);
if(sum!=out[S]){
cout<<"please go home to sleep";
return 0;
}
for(int i=head[S];i;i=e[i].nxt) e[i].flow=e[i^1].flow=0;
for(int i=head[T];i;i=e[i].nxt) e[i].flow=e[i^1].flow=0;
for(int i=head[ed];i;i=e[i].nxt){
int y=e[i].ver;
if(y==st){
sum=e[i^1].flow;
e[i].flow=e[i^1].flow=0;
break;
}
}
cout<<sum+dinner(st,ed);
return 0;
}
无源汇有上下界可行流(输出方案)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=206,M=3e4+1;
const ll inf=(1ll<<60);
int n,m,S,T,tot=1,head[N],now[N],dis[N];
ll ind[N],oud[N],sum;
struct Node{
int ver,nxt;
ll flow,min;
}e[M];
template <typename T>
inline void read(T &x){
x=0;
int f=1;
char ch=getchar();
while(!isdigit(ch)){
if(ch=='-') f=-1;
ch=getchar();
}
while(isdigit(ch)){
x=x*10+(ch-'0');
ch=getchar();
}
x*=f;
}
inline void add(int x,int y,ll f,ll mini){
tot++;
e[tot].ver=y;
e[tot].nxt=head[x];
e[tot].flow=f;
e[tot].min=mini;
head[x]=tot;
}
inline bool bfs(){
memset(dis,0,sizeof dis);
queue<int> q;
q.push(S);
dis[S]=1,now[S]=head[S];
while(!q.empty()){
int x=q.front();
q.pop();
for(int i=head[x];i;i=e[i].nxt){
int y=e[i].ver,f=e[i].flow;
if(f&&!dis[y]){
dis[y]=dis[x]+1;
now[y]=head[y];
if(y==T) return true;
q.push(y);
}
}
}
return false;
}
inline ll dfs(int x,ll minf){
if(x==T) return minf;
ll res=0;
for(int i=now[x];i&&minf;i=e[i].nxt){
int y=e[i].ver;
ll f=e[i].flow;
if(f&&dis[y]==dis[x]+1){
ll k=dfs(y,min(minf,f));
if(!k) dis[y]=0;
res+=k,minf-=k;
e[i].flow-=k;
e[i^1].flow+=k;
}
}
return res;
}
int main(){
read(n),read(m);
for(int i=1,x,y,l,r;i<=m;i++){
read(x),read(y);
read(l),read(r);
add(x,y,r-l,l);
add(y,x,0,0);
ind[y]+=l;
oud[x]+=l;
}
S=n+1,T=n+2;
for(int i=1;i<=n;i++){
if(ind[i]<oud[i]){
add(i,T,oud[i]-ind[i],0);
add(T,i,0,0);
ind[T]+=oud[i]-ind[i];
}
if(ind[i]>oud[i]){
add(S,i,ind[i]-oud[i],0);
add(i,S,0,0);
oud[S]+=ind[i]-oud[i];
}
}
while(bfs()) sum+=dfs(S,inf);
if(oud[S]!=sum){
cout<<"NO\n";
return 0;
}
cout<<"YES\n";
for(int i=2;i<=2+2*m-1;i+=2) cout<<e[i^1].flow+e[i].min<<"\n";
return 0;
}
有向无环图最小路径覆盖
#include<bits/stdc++.h>
using namespace std;
const int N=201,M=6001;
int n,m,tot,head[N],ver[M],nxt[M];
int rm[N],lm[N],ans;
bool vis[N];
inline void add(int x,int y){
tot++;
ver[tot]=y;
nxt[tot]=head[x];
head[x]=tot;
}
inline bool dfs(int x){
for(int i=head[x];i;i=nxt[i]){
int y=ver[i];
if(vis[y]) continue;
vis[y]=true;
if(!rm[y]||dfs(rm[y])){
rm[y]=x;
return true;
}
}
return false;
}
inline void print(int s){
for(int i=s;i;i=lm[i]){
cout<<i<<" ";
vis[i]=true;
}
cout<<"\n";
}
int main(){
ios::sync_with_stdio(0);
cin>>n>>m;
for(int i=1,x,y;i<=m;i++){
cin>>x>>y;
add(x,y);
}
for(int i=1;i<=n;i++){
memset(vis,0,sizeof vis);
dfs(i);
}
for(int i=1;i<=n;i++) lm[rm[i]]=i;
memset(vis,0,sizeof vis);
for(int i=1;i<=n;i++)
if(!vis[i]){
print(i);
ans++;
}
cout<<ans;
return 0;
}
二分图最大匹配
#include<bits/stdc++.h>
using namespace std;
const int N=101,M=2501;
int n,m,tot,head[N],ver[M],nxt[M];
int match[N],ans;
bool vis[N];
inline void add(int x,int y){
tot++;
ver[tot]=y;
nxt[tot]=head[x];
head[x]=tot;
}
inline bool dfs(int x){
for(int i=head[x];i;i=nxt[i]){
int y=ver[i];
if(vis[y]) continue;
vis[y]=true;
if(!match[y]||dfs(match[y])){
match[y]=x;
return true;
}
}
return false;
}
int main(){
ios::sync_with_stdio(0);
cin>>n>>m;
int x,y;
while(cin>>x>>y) add(x,y);
for(int i=1;i<=m;i++){
memset(vis,0,sizeof vis);
if(dfs(i)) ans++;
}
cout<<ans;
return 0;
}
最小费用最大流
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=401,M=3e4+1;
int n,m,S,T,tot=1,head[N],pre[N];
ll dis[N],flw[N],ansflow,anscost;
bool vis[N];
struct Node{
int ver,nxt;
ll flow,cost;
}e[M];
inline void add(int x,int y,int f,int c){
tot++;
e[tot].ver=y;
e[tot].cost=c;
e[tot].flow=f;
e[tot].nxt=head[x];
head[x]=tot;
}
inline bool spfa(){
memset(dis,0x3f,sizeof dis);
memset(flw,0x3f,sizeof flw);
memset(vis,0,sizeof vis);
queue<int> q;
dis[S]=0,vis[S]=true;
q.push(S);
while(!q.empty()){
int x=q.front();
q.pop();
vis[x]=false;
for(int i=head[x];i;i=e[i].nxt){
int y=e[i].ver;
ll c=e[i].cost;
if(e[i].flow&&dis[y]>dis[x]+c){
dis[y]=dis[x]+c;
flw[y]=min(flw[x],e[i].flow);
pre[y]=i;
if(!vis[y]){
q.push(y);
vis[y]=true;
}
}
}
}
return dis[T]!=dis[0];
}
inline void update(){
int x=T;
while(x!=S){
int i=pre[x];
e[i].flow-=flw[T];
e[i^1].flow+=flw[T];
x=e[i^1].ver;
}
ansflow+=flw[T];
anscost+=flw[T]*dis[T];
}
int main(){
ios::sync_with_stdio(0);
cin>>n>>m;
S=1,T=n;
for(int i=1,x,y,f,c;i<=m;i++){
cin>>x>>y>>f>>c;
add(x,y,f,c);
add(y,x,0,-c);
}
while(spfa()) update();
cout<<ansflow<<" "<<anscost;
return 0;
}
本文介绍了几种常见的算法,包括基于AC自动机的字符串匹配,马拉车算法,后缀数组的构造,以及不同类型的网络流问题解决方法,如最大流、有源汇有上下界最大流和最小费用最大流。
469

被折叠的 条评论
为什么被折叠?



