Loading

题解:CF724E Goods transportation

可以在 cnblog 中阅读。

题意

\(n\) 座城市,第 \(i\) 座城市生产了 \(p_i\) 件货物,最多可以出售 \(s_i\) 件货物,编号小的城市可以向编号大的城市运输至多 \(c\) 件货物,问最多能出售多少货物。

\(n \le 10^4\)

分析

乍一看是一个网络流问题,可以这样建图,令 \(S\) 为源点 \(T\) 为汇点:

\[S \xrightarrow{p_i} i \xrightarrow{s_i} T \]

\[i \xrightarrow{c} j (i < j) \]

然后跑一个最大流就可以。但这样建边第二类就会有 \(O(n^2)\) 条边,寄。

模拟费用流就是应对这样的情况的。我们把最大流问题转换为最小割问题,然后考虑使用 DP 求解。

\(f(i,j)\) 表示前 \(i\) 个点,\(j\) 个点与 \(S\) 的连边未断开,注意到 \((S,i)\)\((i,T)\) 必断其一,则有转移:

\[f(i,j) = \min \begin{cases} f(i-1,j) + p_i + c \times j \\ f(i-1,j-1) + s_i \end{cases}\]

分别表示:

  1. 断开 \((S,i)\) 需要断开与前面所有未断开与 \(S\) 连边的点的连边;
  2. 断开 \((i,T)\)

时间复杂度 \(O(n^2)\)

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define IOS ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)

const int N=1e5+5;
int n,c;
int s[N],p[N];
int f[N];

signed main()
{
	IOS;
	cin>>n>>c;
	for(int i=1;i<=n;i++) cin>>p[i];
	for(int i=1;i<=n;i++) cin>>s[i];
	for(int i=1;i<=n;i++)
	{
		f[i]=f[i-1]+s[i];
		for(int j=i-1;j>=1;j--)
			f[j]=min(f[j]+c*j+p[i],f[j-1]+s[i]);
		f[0]+=p[i];
	}
	int ans=1e16;
	for(int i=0;i<=n;i++) ans=min(ans,f[i]);
	cout<<ans<<endl;
	return 0;
}
posted @ 2024-10-03 10:46  tai_chi  阅读(13)  评论(0编辑  收藏  举报