版权声明:原创,未经作者允许禁止转载 https://blog.csdn.net/Mr_wuyongcong/article/details/89281824
正题
题目大意
有
个人
辆车。
人有
,车有
。第i个人修第j俩车时间是
。
一辆车要每个人都修一遍,且一个人修好后要求下一个人没有工作。对于每辆车找一个修理开始时间要求总修理时间最小(得按顺序修)。
解题思路
定义
设
表示第
辆车开始的时间,然后答案就是
且有
时间复杂度
愉快
,我们考虑斜率优化
对于决策
,且
比
优
那有
然后我们发现
并不是单调递增的,但是
肯定越大越优,所以我们可以按照
维护一个单调递增的单调队列,然后就可以对于每个
在单调队列上二分。
时间复杂度
#include<cstdio>
#include<algorithm>
#define ll long long
using namespace std;
const ll N=110000;
ll n,m,t[N],f[N],q[N],g[N],tail;
double tan_(ll x,ll y)
{return (t[x]-t[y])/(double)(t[x-1]-t[y-1]);}
int main()
{
scanf("%lld%lld",&n,&m);
for(ll i=1;i<=n;i++)
scanf("%lld",&t[i]),t[i]+=t[i-1];
for(ll i=1;i<=m;i++)
scanf("%lld",&f[i]);
for(ll i=1;i<=n;i++){
while(tail>1&&tan_(i,q[tail])>tan_(q[tail],q[tail-1]))
tail--;
q[++tail]=i;
}
for(ll i=2;i<=m;i++){
ll l=0,r=tail;
double k=(double)f[i]/(double)f[i-1];
while(l<r){
ll mid=(l+r)/2;
if(tan_(q[mid+1],q[mid])>k) l=mid+1;
else r=mid;
}
g[i]=g[i-1]+t[q[l]]*f[i-1]-t[q[l]-1]*f[i];
}
printf("%lld",g[m]+t[n]*f[m]);
}