CF717G Underfail 题解
RedLycoris · · 题解
此题我们可以考虑费用流
我们考虑建出一张
首先对于
然后,我们对于所有的
然后以
然后解释一下为什么这么建图是正确的:
建立从
那么为什么建立从
我们考虑一下,把那
然后我们再尝试着把这张图拍扁。
如果对于一个点,它对应的字符出现了多于
它上面那些“高速公路”上的流量,最终一定会都流到“主路”上!
然而,如果他对应了多余
那么为什么要建立这看似多余的第
其实很简单,万一有很多高速公路在
Code:
#include<bits/stdc++.h>
#define mp make_pair
#define pii pair<int,int>
using namespace std;
const int mxv=5005;
const int mxn=50005;
const int inf=1000000007;
struct edge{int to,cap,cost,rev;};
int V,m,s,t;
vector<edge>g[mxv],tmpg[mxv];
int h[mxv],dist[mxv],prevv[mxv],preve[mxv];
inline void add_edge(int from,int to,int cap,int cost){
g[from].push_back((edge){to,cap,cost,g[to].size()});
g[to].push_back((edge){from,0,-cost,g[from].size()-1});
}
inline int min_cost_flow(int f){
int res=0;
fill(h,h+V+1,0);
while(f>0){
priority_queue<pii,vector<pii>,greater<pii> >que;
fill(dist,dist+V+1,inf);
dist[s]=0;
que.push(mp(0,s));
for(;!que.empty();){
pii p=que.top();
que.pop();
int v=p.second;
if(dist[v]<p.first)continue;
for(int i=0;i<g[v].size();++i){
edge&e=g[v][i];
if(e.cap>0 and dist[e.to]>dist[v]+e.cost+h[v]-h[e.to]){
dist[e.to]=dist[v]+e.cost+h[v]-h[e.to];
prevv[e.to]=v;
preve[e.to]=i;
que.push(mp(dist[e.to],e.to));
}
}
}
if(dist[t]==inf) return -1;
for(int v=1;v<=V;++v) h[v]+=dist[v];
int d=f;
for(int v=t;v!=s;v=prevv[v]) d=min(d,g[prevv[v]][preve[v]].cap);
f-=d;
res+=d*h[t];
for(int v=t;v!=s;v=prevv[v]){
edge&e=g[prevv[v]][preve[v]];
e.cap-=d;
g[v][e.rev].cap+=d;
}
}
return res;
}
int lev[mxn],iter[mxn];
inline void bfs(){
memset(lev,-1,sizeof(lev));
queue<int>q;
lev[s]=0;
q.push(s);
for(;q.size();){
int v=q.front();q.pop();
for(int i=0;i<g[v].size();++i){
edge&e=g[v][i];
if(e.cap>0 and lev[e.to]<0){
lev[e.to]=lev[v]+1;
q.push(e.to);
}
}
}
}
int dfs(int v,int t,int f){
if(v==t)return f;
for(int&i=iter[v];i<g[v].size();++i){
edge&e=g[v][i];
if(e.cap>0 and lev[v]<lev[e.to]){
int d=dfs(e.to,t,min(f,e.cap));
if(d>0){
e.cap-=d;
g[e.to][e.rev].cap+=d;
return d;
}
}
}
return 0;
}
inline int max_flow(){
int flow=0;
for(;;){
bfs();
if(lev[t]==-1)return flow;
memset(iter,0,sizeof(iter));
int f=0;
for(;;){
f=dfs(s,t,inf);
if(f==0) break;
flow+=f;
}
}
return flow;
}
inline void prep(){for(int i=1;i<=V;++i)tmpg[i]=g[i];}
inline void updg(){for(int i=1;i<=V;++i)g[i]=tmpg[i];}
int n,w,x;string ss;
inline void read(){
cin>>n>>ss>>w;
for(int i=1;i<=w;++i){
string tt;int v;
cin>>tt>>v;
for(int j=0;j<ss.size()-tt.size()+1;++j){
bool fit=1;
for(int k=0;k<tt.size();++k){
if(tt[k]!=ss[j+k]){
fit=0;
break;
}
}
if(fit==1)add_edge(j+1,j+tt.size()+1,1,-v);//这是最小费用最大流的板子,要处理最大费用流的话,就要将边权取负,跑最小费用流,再将答案取负就可以了
}
}
s=1,t=n+2;
V=n+2;
cin>>x;
for(int i=1;i<=n+1;++i)add_edge(i,i+1,x,0);
prep();
}
int main(){
read();
int MaxFlow=max_flow();
updg();
cout<<-min_cost_flow(MaxFlow)<<endl;
}