【CF717G】Underfail
题意:赌城拉斯维起司的赌场最近推出了一种新式赌法。它的玩法是由庄家(Joker)设局,赌徒只需要交付一定数额的赌资即可入局。具体地,Joker将给出一个长度为 $n$ 的由小写字母组成的字符串 $s$ ,再给出 $m$ 个赏金串 $t_1,t_2...t_m$ ,每个赏金串都有一个价值 $w_i$ 。如果 $s$ 的某个子串 $s[l..r]$ 与 $t_i$ 相同,则赌徒可以将 $s[l..r]$ 中的所有字符取走一个,并获得 $w_i$ 的赏金。每个字符最多可以被取走 $k$ 次(注意取完之后两边的字符串是不拼到一起的,想什么呢!)。特别地,每个赏金串只能在同一位置使用一次。即:如果 $s[l..r]=t_i$ ,则赌徒不可以连续在 $s[l..r]$ 处取走两遍的 $t_i$ 并获得 $2w_i$ 的赏金。
一旁的Jack忍不住了,他也想进去捞一笔。不过首先他想知道Joker是否是在坑人(坑鼠),所以他想问问你,他最多能从中获得多少赏金。
$1le nle 500,1le mle 100,1le len{t_i}le 100,0le w_ile 100,1le kle 100$
题解:傻逼费用流~
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include <queue> using namespace std; int n,m,cnt,S,T,ans; int to[100000],nxt[100000],head[510],cost[100000],flow[100000],pe[510],pv[510],dis[510],inq[510]; char s1[510],s2[510]; queue<int> q; inline void add(int a,int b,int c,int d) { to[cnt]=b,cost[cnt]=c,flow[cnt]=d,nxt[cnt]=head[a],head[a]=cnt++; to[cnt]=a,cost[cnt]=-c,flow[cnt]=0,nxt[cnt]=head[b],head[b]=cnt++; } inline int bfs() { memset(dis,0xc0,sizeof(dis)); dis[S]=0,q.push(S); int i,u; while(!q.empty()) { u=q.front(),inq[u]=0,q.pop(); for(i=head[u];i!=-1;i=nxt[i]) if(dis[to[i]]<dis[u]+cost[i]&&flow[i]) { dis[to[i]]=dis[u]+cost[i],pe[to[i]]=i,pv[to[i]]=u; if(!inq[to[i]]) q.push(to[i]),inq[to[i]]=1; } } return dis[T]>0; } int main() { scanf("%d%s%d",&n,s1+1,&m); int i,j,k,a,b; memset(head,-1,sizeof(head)); for(i=1;i<=m;i++) { scanf("%s%d",s2,&b),a=strlen(s2); for(j=1;j+a-1<=n;j++) { for(k=0;k<a;k++) if(s1[j+k]!=s2[k]) break; if(k==a) add(j,j+a,b,1); } } scanf("%d",&a); for(i=0;i<=n;i++) add(i,i+1,0,a); S=0,T=n+1; while(bfs()) { ans+=dis[T]; for(i=T;i!=S;i=pv[i]) flow[pe[i]]--,flow[pe[i]^1]++; } printf("%d",ans); return 0; }