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
这题完成的时间是有负数的,但是似乎费用系数Fi没负数。
明明两个输入的描述是一样的。。也不知道出题人在想什么。。或者说毕竟SDOI么
我们考虑从后往前转移 F,T均为后缀和
f[i]=min(f[j]+(Ti-Tj+S)*Fi)
大概这样一个转移式。
假设j<k,j比k优,
即f[j]+(Ti-Tj+S)*Fi<f[k]+(Ti-Tk+S)*Fi
移项后得
f[j]-f[k]<Fi*(Tj-Tk)
因为T不是单调的所以没办法做除法。
我们考虑cdq分治
假设当前区间是[l,r]
则先把[mid,r]的答案处理出来,然后把[mid,r]中的T按照升序排序
这样就保证了T的单调性,暴力维护出凸壳
然后对于[l,mid],因为F是单调的,所以直接顺着凸壳扫过去找到最优转移位置就可以了
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
using namespace std;
struct quest
{
long long t,f;
long long fx;
int p;
}a[300005],b[300005];
inline bool cmp(quest x,quest y)
{
return x.p<y.p;
}
int q[300005];
long long f[300005];
long long s;
inline bool check(int x,int y,int z)
{
return (a[z].t-a[y].t)*(a[y].fx-a[x].fx)>=(a[z].fx-a[y].fx)*(a[y].t-a[x].t);
}
inline bool getk(int x,int y,long long z)
{
return (a[y].fx-a[x].fx)<z*(a[y].t-a[x].t);
}
inline long long calc(int x,int i)
{
return a[x].fx+a[i].f*(a[i].t-a[x].t+s);
}
inline void solve(int ll,int rr)
{
if(ll==rr-1)
{
return ;
}
int mid=(ll+rr)/2;
solve(mid,rr);
int i;
int l=1,r=0;
for(i=rr-1;i>=mid;i--)
{
while(r>1&&check(q[r-1],q[r],i))
r--;
r++;
q[r]=i;
}
for(i=mid-1;i>=ll;i--)
{
while(l<r&&getk(q[l],q[l+1],a[i].f))
l++;
a[i].fx=min(a[i].fx,calc(q[l],i));
}
solve(ll,mid);
int d1=rr-1,d2=mid-1;
for(i=rr-1;i>=ll;i--)
{
if(d1<=mid-1)
{
b[i]=a[d2];
d2--;
}
else if(d2<=ll-1)
{
b[i]=a[d1];
d1--;
}
else
{
if(a[d2].t<a[d1].t||a[d2].t==a[d1].t)
{
b[i]=a[d2];
d2--;
}
else
{
b[i]=a[d1];
d1--;
}
}
}
for(i=ll;i<=rr-1;i++)
a[i]=b[i];
}
int main()
{
int n;
scanf("%d%lld",&n,&s);
int i;
for(i=1;i<=n;i++)
{
scanf("%lld%lld",&a[i].t,&a[i].f);
a[i].p=i;
}
for(i=n;i>=1;i--)
{
a[i].t=a[i+1].t+a[i].t;
a[i].f=a[i+1].f+a[i].f;
a[i].fx=a[i].f*(a[i].t+s);
}
solve(1,n+1);
sort(a+1,a+1+n,cmp);
printf("%lld\n",a[1].fx);
return 0;
}