1607:【 例 2】任务安排 2
时间限制: 1000 ms 内存限制: 524288 KB【题目描述】
有 N 个任务排成一个序列在一台机器上等待执行,它们的顺序不得改变。机器会把这 N 个任务分成若干批,每一批包含连续的若干个任务。从时刻 0 开始,任务被分批加工,执行第i个任务所需的时间是 Ti。另外,在每批任务开始前,机器需要 S 的启动时间,故执行一批任务所需的时间是启动时间 S 加上每个任务所需时间之和。
一个任务执行后,将在机器中稍作等待,直至该批任务全部执行完毕。也就是说,同一批任务将在同一时刻完成。每个任务的费用是它的完成时刻乘以一个费用系数 Ci 。
请为机器规划一个分组方案,使得总费用最小。
【输入】
第一行是 N。第二行是 S。
下面 N 行每行有一对正整数,分别为 Ti和 Ci ,表示第 i 个任务单独完成所需的时间是 Ti 及其费用系数 Ci 。
【输出】
一个数,最小的总费用。
【输入样例】
5
1
1 3
3 2
4 3
2 3
1 4
【输出样例】
153
【提示】
数据范围与提示:
对于全部数据,1≤N≤104,0≤S≤50,1≤Ti,Ci≤100。
虽然久了点,但全部都是靠抄了一道板子题后自己的理解做出来的qaq
sol:
dp[i]表示到第i个任务话费的最小值
dp[i]=min(dp[i],dp[j]+S*(Cost[n]-Cost[j])+Time[i]*(Cost[i]-Cost[j])) ---->(n2做法见例一)
设j<k<i,若k比j优 (Ps:为了方便C表示Cost,T表示Time)
则dp[k]+S*(C[n]-C[k])+T[i]*(C[i]-C[k])<=dp[j]+S*(C[n]-C[j])+T[i]*(C[i]-C[j])
把括号拆掉 dp[k]+S*C[n]-S*C[k]+T[i]*C[i]-T[i]*C[k]<=dp[j]+S*C[n]-S*C[j]+T[i]*C[i]-T[i]*C[j]
消去同类 dp[k]-S*C[k]-T[i]*C[k]<=dp[j]-S*C[j]-T[i]*C[j]
移项得 dp[k]-dp[j]<=(S+T[i])*(C[k]-C[j]) 条件1
则(条件1)成立时 k 比 j 优 ,否则 j 比 k 优
(dp[k]-dp[j]) / (C[k]-C[j]) 是斜率
代码应该可以出来了
#include <bits/stdc++.h> using namespace std; typedef int ll; inline ll read() { ll s=0; bool f=0; char ch=' '; while(!isdigit(ch)) { f|=(ch=='-'); ch=getchar(); } while(isdigit(ch)) { s=(s<<3)+(s<<1)+(ch^48); ch=getchar(); } return (f)?(-s):(s); } #define R(x) x=read() inline void write(ll x) { if(x<0) { putchar('-'); x=-x; } if(x<10) { putchar(x+'0'); return; } write(x/10); putchar((x%10)+'0'); return; } #define W(x) write(x),putchar(' ') #define Wl(x) write(x),putchar(' ') const int N=10005; int n,S,Time[N],Cost[N]; int dp[N]; int Que[N]; inline bool Panduan(int j,int k,int i) //j<k<i { int S1=dp[k]-dp[j]; int S2=(S+Time[i])*(Cost[k]-Cost[j]); return (S1<=S2)?(1):(0); } inline bool Panduan_Rev(int j,int k,int i) //j<k<i { int S1=(dp[k]-dp[j])*(Cost[i]-Cost[k]); int S2=(dp[i]-dp[k])*(Cost[k]-Cost[j]); return (S1>=S2)?(1):(0); } int main() { int i,Head=1,Tail=1; R(n); R(S); for(i=1;i<=n;i++) { Time[i]=Time[i-1]+read(); Cost[i]=Cost[i-1]+read(); } dp[0]=0; Que[1]=0; for(i=1;i<=n;i++) { while(Head<Tail&&Panduan(Que[Head],Que[Head+1],i)) Head++; int j=Que[Head]; dp[i]=dp[j]+S*(Cost[n]-Cost[j])+Time[i]*(Cost[i]-Cost[j]); while(Head<Tail&&Panduan_Rev(Que[Tail-1],Que[Tail],i)) Tail--; Que[++Tail]=i; } Wl(dp[n]); return 0; } /* input 5 1 1 3 3 2 4 3 2 3 1 4 output 153 */