【CF717G】Underfail 费用流

【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是否是在坑人(坑鼠),所以他想问问你,他最多能从中获得多少赏金。

$1\le n\le 500,1\le m\le 100,1\le len\{t_i\}\le 100,0\le w_i\le 100,1\le k\le 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;
}
posted @ 2018-03-19 08:37 CQzhangyu 阅读(...) 评论(...) 编辑 收藏