Description
机 器上有N个需要处理的任务,它们构成了一个序列。这些任务被标号为1到N,因此序列的排列为1,2,3...N。这N个任务被分成若干批,每批包含相邻的 若干任务。从时刻0开始,这些任务被分批加工,第i个任务单独完成所需的时间是Ti。在每批任务开始前,机器需要启动时间S,而完成这批任务所需的时间是 各个任务需要时间的总和。注意,同一批任务将在同一时刻完成。每个任务的费用是它的完成时刻乘以一个费用系数Fi。请确定一个分组方案,使得总费用最小。
Input
第一行两个整数,N,S。
接下来N行每行两个整数,Ti,Fi。
Output
一个整数,为所求的答案。
Sample Input
5 1
1 3
3 2
4 3
2 3
1 4
1 3
3 2
4 3
2 3
1 4
Sample Output
153
正解:cdq分治+斜率优化
解题报告:大体同上一篇cash的题解相同,但是有一个特别奇妙的地方(网络流好题 修车),
对于每一次分组,我们不是通过前面分了多少组来算它的费用,而是把在这里分组而对后面产生
的影响记在自己身上(因为在这里分一组之后,后面的每一组的时间都要加s+∑t),
所以我们能得出转移方程:dp[i]=min{dp[j]+s*(f[n]-f[j])+t[i]*(f[i]-f[j])}(t数组记得
是时间的前缀和,f数组记得是费用的前缀和);然后再把它拆开:dp[j]+s*f[n]-s*f[j]+t[i]*f[i]-t[i]*f[j]
s乘f[n]是一个定值,t[i]*f[i]只跟i有关,我们把它们视为常数,然后式子变成dp[j]+s*f[j]-t[i]*f[j];
dp[j]+s*f[j]只跟j有关,视为b,t[i]当为x,f[j]当为k,然后就成为了kx+b的形式,再套上cdq维护
x与k的单调性就可以用斜率优化了,时间复杂度O(nlogn)。
#include <iostream>
#include <iomanip>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#define RG register
#define int long long
#define ld long double
#define File(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout)
const int N = 400000;
using namespace std;
int gi(){
char ch=getchar();int x=0,q=0;
while(ch<'0' || ch>'9') {if (ch=='-') q=1;ch=getchar();}
while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
return q? (-x) : x;
}
int n,s;
int t[N],f[N],dp[N];
struct date{
double k,x,b;int t;
bool operator < (const date &a) const{
return x<a.x;
}
}g[N],st[N],p[N];
inline void cdq(int l,int r){
if (l==r) return;
int mid=(l+r)>>1,p1=l,p2=mid+1,head=1,tail=0;
for (RG int i=l; i<=r; ++i)
if (g[i].t<=mid) p[p1++]=g[i];
else p[p2++]=g[i];
for (RG int i=l; i<=r; ++i) g[i]=p[i];
cdq(l,mid);
for (RG int i=l; i<=mid; ++i){
while(head<tail && (ld)(st[tail-1].b-st[tail].b)*(g[i].k-st[tail-1].k)>=(ld)(st[tail-1].b-g[i].b)*(st[tail].k-st[tail-1].k)) --tail;
st[++tail]=g[i];
}
sort(g+mid+1,g+r+1);
for (RG int i=mid+1; i<=r; ++i){
while(head<tail && st[head].k*g[i].x+st[head].b>=st[head+1].k*g[i].x+st[head+1].b) ++head;
dp[g[i].t]=min((double)dp[g[i].t],st[head].k*g[i].x+f[n]*s+st[head].b+t[g[i].t]*f[g[i].t]);
g[i].b=dp[g[i].t]-s*f[g[i].t];
}
cdq(mid+1,r);p1=l,p2=mid+1;
for (RG int i=l; i<=r; ++i)
if (p2>r || (p1<=mid && g[p1].k>=g[p2].k)) p[i]=g[p1++];
else p[i]=g[p2++];
for (RG int i=l; i<=r; ++i) g[i]=p[i];
return;
}
main(){
File("work");
n=gi(),s=gi();
for (RG int i=1; i<=n; ++i) t[i]=gi()+t[i-1],f[i]=gi()+f[i-1];
for (RG int i=1; i<=n; ++i){
dp[i]=s*f[n]+t[i]*f[i];
g[i]=(date){-f[i],t[i],dp[i]-s*f[i],i};
}
cdq(1,n);
printf("%lld",dp[n]);
return 0;
}