一本通1608【 例 3】任务安排 3
1608:【 例 3】任务安排 3
时间限制: 1000 ms 内存限制: 524288 KB【题目描述】
有 N 个任务排成一个序列在一台机器上等待执行,它们的顺序不得改变。机器会把这 N 个任务分成若干批,每一批包含连续的若干个任务。从时刻 0 开始,任务被分批加工,执行第i个任务所需的时间是 Ti。另外,在每批任务开始前,机器需要 S 的启动时间,故执行一批任务所需的时间是启动时间 S 加上每个任务所需时间之和。
一个任务执行后,将在机器中稍作等待,直至该批任务全部执行完毕。也就是说,同一批任务将在同一时刻完成。每个任务的费用是它的完成时刻乘以一个费用系数 Ci 。
请为机器规划一个分组方案,使得总费用最小。
【输入】
第一行两个整数,分别为 N,S;
接下来 N 行每行两个整数 Ti,Ci 。
【输出】
一个数,最小的总费用。
【输入样例】
5 1
1 3
3 2
4 3
2 3
1 4
【输出样例】
153
【提示】
数据范围与提示:
对于全部数据,1≤N≤3×105,1≤S≤28,|Ti|≤28,0≤Ci≤28。
sol:这次的Ti可以是负的,所以就没有单调性了,但是凸包还是有单调性的,所有二分当前直线与凸包的切点就可以了(题解原话)
#include <bits/stdc++.h> using namespace std; typedef long long 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('\n') const int N=300005; int n,S; ll Time[N],Cost[N]; ll dp[N]; int Que[N]; inline bool Panduan_Rev(int j,int k,int i) //j<k<i { ll S1=(dp[k]-dp[j])*(Cost[i]-Cost[k]); ll S2=(dp[i]-dp[k])*(Cost[k]-Cost[j]); return (S1>=S2)?(1):(0); } int main() { // freopen("arrangement1.in","r",stdin); int i; R(n); R(S); for(i=1;i<=n;i++) { Time[i]=Time[i-1]+read(); Cost[i]=Cost[i-1]+read(); } int Head=1,Tail=1; Que[1]=dp[0]=0; for(i=1;i<=n;i++) { int l=1,r=Tail,Pos=1; while(l<=r) { int mid=(l+r)>>1; if(dp[Que[mid]]-dp[Que[mid-1]]<=(S+Time[i])*(Cost[Que[mid]]-Cost[Que[mid-1]])) { Pos=mid; l=mid+1; } else r=mid-1; } dp[i]=dp[Que[Pos]]+S*(Cost[n]-Cost[Que[Pos]])+Time[i]*(Cost[i]-Cost[Que[Pos]]); 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 */
河田は河田、赤木は赤木……。
私は誰ですか。教えてください、私は誰ですか。
そうだ、俺はあきらめない男、三井寿だ!