类似志愿者招募的建图方法
用一个点表示差分 然后用流量表示出差分的和
然后在l,r+1之间连边
这是个无源汇最大费用可行流
我是这么做的
#include<cstdio>
#include<cstdlib>
#include<algorithm>
using namespace std;
inline char nc(){
static char buf[100000],*p1=buf,*p2=buf;
if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; }
return *p1++;
}
inline void read(int &x){
char c=nc(),b=1;
for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}
inline int read(char *s){
int len=0; char c=nc();
for (;!(c>='a' && c<='z');c=nc());
for (;c>='a' && c<='z';s[++len]=c,c=nc()); s[++len]=0; return len-1;
}
const int N=505;
struct edge{
int u,v,w,f,next;
}G[500005];
int head[N],inum=1;
inline void add(int u,int v,int w,int f,int p){
G[p].u=u; G[p].v=v; G[p].w=w; G[p].f=f; G[p].next=head[u]; head[u]=p;
}
inline void link(int u,int v,int w,int f){
add(u,v,w,f,++inum); add(v,u,-w,0,++inum);
}
int S,T;
int dis[N],ins[N],pre[N];
const int NQ=1000005;
#define ad(x) ((x)+1==NQ?(x)=0:++(x))
int Q[NQ],l,r;
int Maxcost;
#define V G[p].v
inline bool SPFA(){
for (int i=1;i<=T;i++) dis[i]=1<<30,ins[i]=0,pre[i]=0;
l=-1,r=-1;
Q[ad(r)]=S; dis[S]=0; ins[S]=1;
while (l!=r){
int u=Q[ad(l)]; ins[u]=0;
for (int p=head[u];p;p=G[p].next)
if (G[p].f && dis[V]>dis[u]+G[p].w){
dis[V]=dis[u]+G[p].w; pre[V]=p;
if (!ins[V]) Q[ad(r)]=V,ins[V]=1;
}
}
if (dis[T]==1<<30) return false;
int minimum=1<<30;
for (int p=pre[T];p;p=pre[G[p].u])
minimum=min(minimum,G[p].f);
for (int p=pre[T];p;p=pre[G[p].u]){
G[p].f-=minimum; G[p^1].f+=minimum;
Maxcost-=minimum*G[p].w;
}
return true;
}
int n,m;
char str[N]; int nxt[N];
int len[N],cost[N]; char s[N][N];
inline void addedge(int l,int r,int cost){
r++;
link(l,r,cost,1);
link(r,S,0,1);
link(T,l,0,1);
Maxcost+=cost;
}
inline void KMP(int len,char *s,int cost){
nxt[1]=0; int k=0;
for (int i=2;i<=len;i++){
while (k && s[k+1]!=s[i]) k=nxt[k];
if (s[k+1]==s[i]) k++;
nxt[i]=k;
}
k=0;
for (int i=1;i<=n;i++){
while (k && s[k+1]!=str[i]) k=nxt[k];
if (s[k+1]==str[i]) k++;
if (k==len){
addedge(i-len+1,i,cost);
k=nxt[k];
}
}
}
int main(){
int tem;
freopen("t.in","r",stdin);
freopen("t.out","w",stdout);
read(n); read(str);
read(m);
for (int i=1;i<=m;i++)
len[i]=read(s[i]),read(cost[i]);
read(tem);
for (int i=1;i<=n;i++)
link(i,i+1,0,tem);
S=n+1+1; T=n+1+2;
for (int i=1;i<=m;i++)
KMP(len[i],s[i],cost[i]);
swap(S,T);
while (SPFA());
printf("%d\n",Maxcost);
return 0;
}