洛谷 P2365 任务安排 & 一本通 任务安排1 题解

题目传送门(luogu)
题目传送门(loj)

题目大意: n n n 个任务,你可以将连续的一段一起完成,这一段任务的完成时间为这一段中所有的任务的时间花费之和加上之前的时间花费再加一个 s s s。每个任务的费用是它的完成时间乘以一个费用系数。求最小花费。

题解

一看就是个 d p dp dp 了,设 f [ i ] f[i] f[i] 为前 i i i 个任务的最小花费。

发现题目中的 s s s 不好处理,这里用到一个很优秀的技巧——费用提前

具体是这样的:因为我们不知道之前用了多少个 s s s,所以这里难以计算费用,换句话说,我们不知道之前对现在的贡献,但是,我们知道现在对未来的贡献!假如当前把 x x x ~ y y y 这一段任务一起完成,那么事实上,我们将 x x x ~ n n n 这一段任务的完成时间都延后了 s s s,那么直接加上 ( c [ n ] − c [ x − 1 ] ) × s (c[n]-c[x-1])\times s (c[n]c[x1])×s c c c 是任务费用系数的前缀和)即可。

那么得出方程: f [ i ] = min ⁡ j = 0 i − 1 { f [ j ] + t [ i ] × ( c [ i ] − c [ j ] ) + s × ( c [ n ] − c [ j ] ) } f[i]=\min\limits_{j=0}^{i-1}\{f[j]+t[i]\times (c[i]-c[j])+s\times (c[n]-c[j])\} f[i]=j=0mini1{f[j]+t[i]×(c[i]c[j])+s×(c[n]c[j])}

t t t 是任务的时间花费的前缀和)

代码如下:

#include <cstdio>
#include <cstring>
#define maxn 5010

int n,s;
int t[maxn],c[maxn];
int f[maxn];
inline int min(int x,int y){return x<y?x:y;}

int main()
{
	scanf("%d %d",&n,&s);
	for(int i=1;i<=n;i++)
	scanf("%d %d",&t[i],&c[i]),t[i]+=t[i-1],c[i]+=c[i-1];
	for(int i=1;i<=n;i++)
	{
		f[i]=999999999;
		for(int j=0;j<i;j++)
		f[i]=min(f[i],f[j]+t[i]*(c[i]-c[j])+s*(c[n]-c[j]));
	}
	printf("%d",f[n]);
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值