【bzoj2726】[SDOI2012]任务安排 【cdq分治+斜率优化】
题目传送门
这题和bzoj1492Cash几乎一样,所以这里只贴公式。
=>
=>
=>
=>
然后用cdq分治优化即可。
细节详见代码。
#include<cstdio>
#include<cmath>
#include<algorithm>
typedef long long ll;
using namespace std;
const int N=300005;
int n,q[N];
ll s,f[N];
struct data{
ll t,c;
int id;
friend bool operator < (const data &a,const data &b){
return a.t<b.t;
}
}a[N],b[N];
inline int rd(){
register int res=0,f=1;
register char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-'){
f=-1;
}
ch=getchar();
}
while(ch>='0'&&ch<='9'){
res=res*10+ch-'0';
ch=getchar();
}
return res*f;
}
ll get(int i){
return f[a[i].id]-a[i].c*a[i].t+a[i].c*s;
}
ll getx(int j,int k){
return get(k)-get(j);
}
ll gety(int j,int k){
return a[j].c-a[k].c;
}
void solve(int l,int r){
if(l==r){
return;
}
register int mid=(l+r)/2,j=l,k=mid+1;
for(register int i=l;i<=r;i++){
if(a[i].id<=mid){
b[j++]=a[i];
}else{
b[k++]=a[i];
}
}
for(register int i=l;i<=r;i++){
a[i]=b[i];
}
solve(l,mid);
j=1,k=0;
for(register int i=l;i<=mid;i++){
while(j<k&&getx(q[k],i)*gety(q[k-1],q[k])<getx(q[k-1],q[k])*gety(q[k],i)){
k--;
}
q[++k]=i;
}
for(register int i=mid+1;i<=r;i++){
while(j<k&&getx(q[j],q[j+1])<=a[i].t*gety(q[j],q[j+1])){
j++;
}
if(j<=k){
f[a[i].id]=min(f[a[i].id],f[a[q[j]].id]+a[q[j]].c*(a[i].t-a[q[j]].t+s));
}
}
solve(mid+1,r);
j=l,k=mid+1;
for(register int i=l;i<=r;i++){
if(j<=mid&&(k>r||a[j].c>=a[k].c)){
b[i]=a[j++];
}else{
b[i]=a[k++];
}
}
for(register int i=l;i<=r;i++){
a[i]=b[i];
}
}
signed main(){
scanf("%d%lld",&n,&s);
for(register int i=1;i<=n;i++){
scanf("%lld%lld",&a[i].t,&a[i].c);
a[i].t+=a[i-1].t;
a[i].c+=a[i-1].c;
a[i].id=i;
}
ll tmp=a[n].c;
for(register int i=n;i>=0;i--){
a[i].c=tmp-a[i].c;
}
for(register int i=1;i<=n;i++){
f[i]=a[0].c*(a[i].t+s);
}
sort(a+1,a+n+1);
solve(1,n);
printf("%lld",f[n]);
return 0;
}