jzoj 3169. 【GDOI2013模拟4】生产汽车

Description

题目大意,就是有n个人,m辆车;从第一辆车开始做,做到第m辆车;每辆车要连续地从第一个工人做到第n个工人,第i个工人做第j辆车要a[i] * b[j]分钟。求生产完所有汽车最少需要多少时间。

Input

第一行输入两个整数:工人数N(1<=N<=100,000)和汽车数M(1<=M<=100,000)。
接下来N行描述每一个工人的Ti(1<=Ti<=10,000)。
接下来M行描述每一台汽车的Fj(1<=Fj<=10,000)。

Output

输出一个数表示最少需要的时间。

Sample Input

输入1:

3 3
2
1
1
2
1
1

输入2:

3 3
2
3
3
2
1
2

输入3:

4 5
3
2
2
2
3
1
2
1
2

Sample Output

输出1:

11

输出2:

29

输出3:

55

Data Constraint

40%的数据满足N,M<=1000。

Hint

样例1: 4分钟后,工人1完成1号汽车的工作,他可以立刻开始生产第2台汽车,但如果这样的话将会不满足条件,因为7分钟后,工人2完成2号汽车的工作,此时3号工人还在生产1号汽车,3号工人并不空闲,所以2号汽车在5分钟后开始生产,3号汽车在7分钟后开始生产。3台汽车全部生产完共花费11分钟。

Solution

一开始打了个暴力,发现可以斜率优化,推推推。。。
我们发现,对于第i辆车到第j辆车的过程要max(b[i] * a[j] - b[i+1] * a[j-1])(1<=j<=n)
设j>k且j比k更大可得斜率式:

(a[j]-a[k])/(a[j-1]-a[k-1])<b[i+1]/b[i]

Code

#include<cstdio>
#include<algorithm>
#define N 100010
#define ll long long
#define db double
using namespace std;
int n,m,b[N],g[N],tot=0;
ll a[N],sum=0,ans=0;

inline int read()
{
	int x=0; char c=getchar();
	while (c<'0' || c>'9') c=getchar();
	while (c>='0' && c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
	return x;
}

db slope(int x,int y) {return (db)(a[x]-a[y])/(a[x-1]-a[y-1]);}

int main()
{
	freopen("car.in","r",stdin);
//	freopen("car.out","w",stdout); 
	n=read(),m=read();
	for (int i=1;i<=n;i++)
	{
		a[i]=read()+a[i-1];
		while (slope(i,g[tot])>slope(g[tot],g[tot-1]) && tot>1) tot--;
		g[++tot]=i;
	}
	for (int i=1;i<=m;i++) b[i]=read();
	for (int i=1,l,r,mid,s;i<=m;i++)
	{
		l=1,r=tot,s=0;
		while (l<=r)
		{
			mid=l+r>>1;
			if (slope(g[mid],g[mid-1])>(db)b[i+1]/b[i]) s=mid,l=mid+1;
			else r=mid-1;
		}
		ans+=b[i]*a[g[s]]-b[i+1]*a[g[s]-1];
	}
	printf("%lld
",ans);
	return 0;
}
转载需注明出处。
原文地址:https://www.cnblogs.com/jz929/p/11817537.html