[codeforces724E]Goods transportation

[codeforces724E]Goods transportation

试题描述

There are n cities located along the one-way road. Cities are numbered from 1 to n in the direction of the road.

The i-th city had produced pi units of goods. No more than si units of goods can be sold in the i-th city.

For each pair of cities i and j such that 1 ≤ i < j ≤ n you can no more than once transport no more than c units of goods from the city i to the city j. Note that goods can only be transported from a city with a lesser index to the city with a larger index. You can transport goods between cities in any order.

Determine the maximum number of produced goods that can be sold in total in all the cities after a sequence of transportations.

输入

The first line of the input contains two integers n and c (1 ≤ n ≤ 10 000, 0 ≤ c ≤ 109) — the number of cities and the maximum amount of goods for a single transportation.

The second line contains n integers pi (0 ≤ pi ≤ 109) — the number of units of goods that were produced in each city.

The third line of input contains n integers si (0 ≤ si ≤ 109) — the number of units of goods that can be sold in each city.

输出

Print the maximum total number of produced goods that can be sold in all cities after a sequence of transportations.

输入示例

4 3
13 10 7 4
4 7 10 13

输出示例

34

数据规模及约定

见“输入

题解

这显然是一个最大流模型,从源点向每一个城市连一条容量为 pi 的单向边,从每个城市向汇点连一条容量为 si 的单向边,然后每个城市向编号比它大的所有城市连一条容量为 c 的单向边。

然而最多有 10002 个点,50015000 条边,时间暂且不考虑,每条边需要有反向弧,并且每条弧至少需要存 2 个 int(边的终点和边的剩余流量),对于 256MB 的限制来说太大了。

然而这题有一个比较妙的办法,由于建图的特殊性,我们可以转化成最小割之后 dp,设 f(i, j) 表示前 i 个点中 j 个点属于 S 集合的最小割是多少。

第一步:先把从源点到节点 i 再到汇点的流量先耗尽,于是残量网络就变成了这个样子:

  若 pi > si,则从源点向 i 连一条 pi - si 的边;

  若 pi < si,则从 i 向汇点连一条 si - pi 的边;

  若 0 < i < j < n + 1,则从 i 向 j 连一条 c 的边。

第二步:考虑上面的 dp 如何转移,枚举当前点属于 S 集还是 T 集。我很懒,不想再写了,转移方程不妨留给读者思考吧。。。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <cstring>
#include <string>
#include <map>
#include <set>
using namespace std;

const int BufferSize = 1 << 16;
char buffer[BufferSize], *Head, *Tail;
inline char Getchar() {
    if(Head == Tail) {
        int l = fread(buffer, 1, BufferSize, stdin);
        Tail = (Head = buffer) + l;
    }
    return *Head++;
}
int read() {
    int x = 0, f = 1; char c = Getchar();
    while(!isdigit(c)){ if(c == '-') f = -1; c = Getchar(); }
    while(isdigit(c)){ x = x * 10 + c - '0'; c = Getchar(); }
    return x * f;
}

#define maxn 10010
#define oo (1ll << 60)
#define LL long long
LL f[2][maxn];
int n, C, P[maxn], S[maxn];

int main() {
	n = read(); C = read();
	for(int i = 1; i <= n; i++) P[i] = read();
	for(int i = 1; i <= n; i++) S[i] = read();
	
	for(int i = 0; i < 2; i++)
		for(int j = 0; j <= n; j++)
			f[i][j] = oo;
	f[0][0] = 0;
	LL base = 0; bool cur = 1;
	for(int i = 1; i <= n; i++, cur ^= 1) {
		base += min(S[i], P[i]);
		for(int j = 0; j <= n; j++) f[cur][j] = oo;
		for(int j = 0; j <= i; j++) {
			if(S[i] > P[i]) {
				if(j && f[cur^1][j-1] < oo) f[cur][j] = min(f[cur][j], f[cur^1][j-1] + S[i] - P[i]);
				if(f[cur^1][j] < oo) f[cur][j] = min(f[cur][j], f[cur^1][j] + (LL)j * C);
			}
			else {
				if(j && f[cur^1][j-1] < oo) f[cur][j] = min(f[cur][j], f[cur^1][j-1]);
				if(f[cur^1][j] < oo) f[cur][j] = min(f[cur][j], f[cur^1][j] + P[i] - S[i] + (LL)j * C);
			}
		}
	}
	LL tmp = oo;
	for(int i = 0; i <= n; i++) tmp = min(tmp, f[cur^1][i]);
	
	printf("%I64d
", base + tmp);
	
	return 0;
}
原文地址:https://www.cnblogs.com/xiao-ju-ruo-xjr/p/6341104.html