Codeforces 717G Underfail(最小费用最大流 + AC自动机)

题目

Source

http://codeforces.com/problemset/problem/717/G

Description

You have recently fallen through a hole and, after several hours of unconsciousness, have realized you are in an underground city. On one of your regular, daily walks through the unknown, you have encountered two unusually looking skeletons called Sanz and P’pairus, who decided to accompany you and give you some puzzles for seemingly unknown reasons.

One day, Sanz has created a crossword for you. Not any kind of crossword, but a 1D crossword! You are given m words and a string of length n. You are also given an array p, which designates how much each word is worth — the i-th word is worth pi points. Whenever you find one of the m words in the string, you are given the corresponding number of points. Each position in the crossword can be used at most x times. A certain word can be counted at different places, but you cannot count the same appearance of a word multiple times. If a word is a substring of another word, you can count them both (presuming you haven’t used the positions more than x times).

In order to solve the puzzle, you need to tell Sanz what’s the maximum achievable number of points in the crossword. There is no need to cover all postions, just get the maximal score! Crossword and words contain only lowercase English letters.

Input

The first line of the input contains a single integer n (1 ≤ n ≤ 500) — the length of the crossword. The second line contains the crossword string. The third line contains a single integer m (1 ≤ m ≤ 100) — the number of given words, and next m lines contain description of words: each line will have a string representing a non-empty word (its length doesn‘t exceed the length of the crossword) and integer pi (0 ≤ pi ≤ 100). Last line of the input will contain x (1 ≤ x ≤ 100) — maximum number of times a position in crossword can be used.

Output

Output single integer — maximum number of points you can get.

Sample Input

6
abacba
2
aba 6
ba 3
3

Sample Output

12

分析

题目大概说给一个主串和几个有价值的模式串,某个模式串与主串匹配就能累加对应的价值,一个模式串可以在多个位置和主串匹配但同一个位置只能一次,此外主串各个字符最多可以用x次,问如何匹配使获得的价值最大。

各个模式串在主串匹配的位置可以用AC自动机找到,而这些位置相当于区间。

其实这题就相当于在一条数轴上选择最大权和的区间,使得各个点被覆盖的区间数不超过x。区间k覆盖问题,POJ3680。。

我都不会建图了。。要注意的是区间要处理成左闭右开形式,不然比如[1,1]这个区间建图就会出现负环了。

代码

#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
#define INF (1<<30)
#define MAXN 555
#define MAXM 555*1111

struct Edge{
    int u,v,cap,cost,next;
}edge[MAXM];
int head[MAXN];
int NV,NE,vs,vt;

void addEdge(int u,int v,int cap,int cost){
    edge[NE].u=u; edge[NE].v=v; edge[NE].cap=cap; edge[NE].cost=cost;
    edge[NE].next=head[u]; head[u]=NE++;
    edge[NE].u=v; edge[NE].v=u; edge[NE].cap=0; edge[NE].cost=-cost;
    edge[NE].next=head[v]; head[v]=NE++;
}
bool vis[MAXN];
int d[MAXN],pre[MAXN];
bool SPFA(){
    for(int i=0;i<NV;++i){
        vis[i]=0;
        d[i]=INF;
    }
    vis[vs]=1;
    d[vs]=0;
    queue<int> que;
    que.push(vs);
    while(!que.empty()){
        int u=que.front(); que.pop();
        for(int i=head[u]; i!=-1; i=edge[i].next){
            int v=edge[i].v;
            if(edge[i].cap && d[v]>d[u]+edge[i].cost){
                d[v]=d[u]+edge[i].cost;
                pre[v]=i;
                if(!vis[v]){
                    vis[v]=1;
                    que.push(v);
                }
            }
        }
        vis[u]=0;
    }
    return d[vt]!=INF;
}
int MCMF(){
    int res=0;
    while(SPFA()){
        int flow=INF,cost=0;
        for(int u=vt; u!=vs; u=edge[pre[u]].u){
            flow=min(flow,edge[pre[u]].cap);
        }
        for(int u=vt; u!=vs; u=edge[pre[u]].u){
            edge[pre[u]].cap-=flow;
            edge[pre[u]^1].cap+=flow;
            cost+=flow*edge[pre[u]].cost;
        }
        res+=cost;
    }
    return res;
}

int tn,ch[55500][26],fail[55500];
vector<int> vec[55500];
void insert(char *s,int k){
	int x=0;
	for(int i=0; s[i]; ++i){
		int y=s[i]-‘a‘;
		if(ch[x][y]==0) ch[x][y]=++tn;
		x=ch[x][y];
	}
	vec[x].push_back(k);
}
void getfail(){
	queue<int> que;
	for(int i=0; i<26; ++i){
		if(ch[0][i]) que.push(ch[0][i]);
	}
	while(!que.empty()){
		int x=que.front(); que.pop();
		for(int i=0; i<26; ++i){
			if(ch[x][i]){
				fail[ch[x][i]]=ch[fail[x]][i];
				que.push(ch[x][i]);
			}else ch[x][i]=ch[fail[x]][i];
		}
	}
}

int val[111],len[111];
void ac(char *s){
	int x=0;
	for(int i=0; s[i]; ++i){
		int y=s[i]-‘a‘;
		x=ch[x][y];
		for(int tmp=x; tmp; tmp=fail[tmp]){
			for(int j=0; j<vec[tmp].size(); ++j){
				int k=vec[tmp][j];
				addEdge(i-len[k]+1,i+1,1,-val[k]);
			}
		}
	}
}

char S[555],T[555];
int main(){
	int n,m,x;
	scanf("%d%s%d",&n,S,&m);
	for(int i=1; i<=m; ++i){
		scanf("%s%d",T,val+i);
		len[i]=strlen(T);
		insert(T,i);
	}
	scanf("%d",&x);

	vs=n+1; vt=vs+1; NV=vt+1; NE=0;
	memset(head,-1,sizeof(head));
	addEdge(vs,0,x,0);
	addEdge(n,vt,x,0);
	for(int i=1; i<=n; ++i){
		addEdge(i-1,i,INF,0);
	}

	getfail();
	ac(S);

	printf("%d",-MCMF());
	return 0;
}
时间: 2024-12-22 07:00:25

Codeforces 717G Underfail(最小费用最大流 + AC自动机)的相关文章

hdoj 1533 Going Home 【最小费用最大流】【KM入门题】

Going Home Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 3443    Accepted Submission(s): 1763 Problem Description On a grid map there are n little men and n houses. In each unit time, every

POJ--3422--Kaka&#39;s Matrix Travels【最小费用最大流+拆点】

链接:http://poj.org/problem?id=3422 卡卡 题意:卡卡的矩阵之旅,有一个n*n的矩阵,卡卡要从左上角走到右下角,每次他只能往右或往下走,卡卡可以走k遍这个矩阵,每个点有一个num值,卡卡走到这里可以获得num点,一个点只能获得一次num值,问卡卡走完k遍后身上num值最大可以是多少? 思路:其实看到这题时没思路,图论书上说了建图的方式,但没有说为什么,我不解,网上搜了一下解题报告,百度了两页,我看到的博客都是写了如何建图,但没有写为什么要这么建..我觉得我真是弱渣,

网络流(最小费用最大流):POJ 2135 Farm Tour

Farm Tour Time Limit: 1000ms Memory Limit: 65536KB This problem will be judged on PKU. Original ID: 2135 64-bit integer IO format: %lld      Java class name: Main When FJ's friends visit him on the farm, he likes to show them around. His farm compris

LiberOJ #6013. 「网络流 24 题」负载平衡 最小费用最大流 供应平衡问题

#6013. 「网络流 24 题」负载平衡 内存限制:256 MiB时间限制:1000 ms标准输入输出 题目类型:传统评测方式:文本比较 上传者: 匿名 提交提交记录统计讨论测试数据 题目描述 G 公司有 n nn 个沿铁路运输线环形排列的仓库,每个仓库存储的货物数量不等.如何用最少搬运量可以使 n nn 个仓库的库存数量相同.搬运货物时,只能在相邻的仓库之间搬运. 输入格式 文件的第 1 11 行中有 1 11 个正整数 n nn,表示有 n nn 个仓库.第 2 22 行中有 n nn 个

zoj 3885 The Exchange of Items 【最小费用最大流】

The Exchange of Items Time Limit: 2 Seconds      Memory Limit: 65536 KB Bob lives in an ancient village, where transactions are done by one item exchange with another. Bob is very clever and he knows what items will become more valuable later on. So,

洛谷 P3381 【模板】最小费用最大流

题目描述 如题,给出一个网络图,以及其源点和汇点,每条边已知其最大流量和单位流量费用,求出其网络最大流和在最大流情况下的最小费用. 输入输出格式 输入格式: 第一行包含四个正整数N.M.S.T,分别表示点的个数.有向边的个数.源点序号.汇点序号. 接下来M行每行包含四个正整数ui.vi.wi.fi,表示第i条有向边从ui出发,到达vi,边权为wi(即该边最大流量为wi),单位流量的费用为fi. 输出格式: 一行,包含两个整数,依次为最大流量和在最大流量情况下的最小费用. 输入输出样例 输入样例#

poj 2516 Minimum Cost 【最小费用最大流】

题目:poj 2516 Minimum Cost 题意:有 n 个商店,k种物品和 m 个供货商,让你求进满足商店需求的货物的最小花费? 有必要说一下输入数据. 首先n ,k ,m 然后是一个n*m的矩阵,n个商店对每种货物的需求,表示第 i 个商店需要第 j 种货物 x个 然后是m * k 的矩阵,m个供货商可以供k种货物的数量,表示第 i 个供货商 提供第 j 中货物 x 个 接下来是 k 个 n * m 的矩阵,表示第 i 个货物,由 k 供应商发货给 j 商店的价格x (注意如果供不应求

最小费用最大流 POJ2195-Going Home

网络流相关知识参考: http://www.cnblogs.com/luweiseu/archive/2012/07/14/2591573.html 出处:優YoU http://blog.csdn.net/lyy289065406/article/details/6732762 大致题意: 给定一个N*M的地图,地图上有若干个man和house,且man与house的数量一致.man每移动一格需花费$1(即单位费用=单位距离),一间house只能入住一个man.现在要求所有的man都入住hou

【BZOJ3876】【Ahoi2014】支线剧情 有下界的最小费用最大流

#include <stdio.h> int main() { puts("转载请注明出处谢谢"); puts("http://blog.csdn.net/vmurder/article/details/43025375"); } [BZOJ2324]营救皮卡丘 这道题也是一道有下界的最小费用最大流. 我的题解地址:http://blog.csdn.net/vmurder/article/details/41378979 这道题其实就是模板题. 我的处理