2019.4.13 提高A组 T1 JZOJ 3169 生产汽车

版权声明:虽然本蒟蒻很菜,但各位dalao转载请注明出处谢谢。 https://blog.csdn.net/xuxiayang/article/details/89280993

D e s c r i p t i o n Description

n n 个人和 m m 辆汽车,第 i i 个人可以完成第 j j 辆车的第 i i 项工序,耗时 T [ i ] × F [ j ] T[i]\times F[j]

现在必须要从前往后造汽车,但是当 i i 完成他的工序时, i + 1 ( i < n ) i+1(i<n) 这个人必须有空闲去接上他的工序

求最快完成的时间。

数据范围: n , m 1 0 5 n,m\leq 10^5


S o l u t i o n Solution

f [ i ] f[i] 表示第 i i 辆汽车开始生产的时间, f [ 1 ] = 0 f[1]=0

f [ i ] = f [ i 1 ] + m a x ( F [ i 1 ] × s u m [ j ] + F [ i ] × s u m [ j 1 ] ) s u m [ j ] = Σ t [ k ] ( 1 < = k < = j ) f[i]=f[i-1]+max(F[i-1]\times sum[j]+F[i]\times sum[j-1]) 其中sum[j]=Σt[k] (1<=k<=j)

表示每个人都必须在它生产完 i 1 i-1 这辆车之后才能继续第 i i 辆,看到这个十字我们考虑斜率优化

对于决策 j , k j,k k k 优于 j j ,那么有

F [ i 1 ] × s [ j ] + F [ i ] × s [ j 1 ] < F [ i 1 ] × s [ k ] + F [ i ] × s [ k 1 ] F[i-1]\times s[j]+F[i]\times s[j-1]<F[i-1]\times s[k]+F[i]\times s[k-1]

分配率

F [ i 1 ] × ( s [ j ] s [ k ] ) < F [ i ] × ( s [ j 1 ] s [ k 1 ] ) F[i-1]\times(s[j]-s[k])<F[i]\times (s[j-1]-s[k-1])

等式的性质

F [ i 1 ] F [ i ] < s [ j 1 ] s [ k 1 ] s [ j ] s [ k ] \frac{F[i-1]}{F[i]}<\frac{s[j-1]-s[k-1]}{s[j]-s[k]}

但是 F [ i 1 ] F [ i ] \frac{F[i-1]}{F[i]} 不具有单调性,所以我们维护一个斜率单调递减的上凸壳,然后在上面二分

C o d e Code

#pragma GCC opitmize("O3")
#pragma G++ opitmize("O3")
#include<cstdio>
#include<cstring>
#include<cctype>
#include<algorithm>
#define N 100010
using namespace std;
int n,m,q[N],t=0;
long long F[N],s[N],f[N];
inline long long read()
{
    char c;int f=0,d=1;
    while(c=getchar(),!isdigit(c)) if(c=='-') d=-1;f=(f<<3)+(f<<1)+c-48;
    while(c=getchar(),isdigit(c)) f=(f<<3)+(f<<1)+c-48;
    return d*f;
}
inline double slp(int i,int j)
{ 
	return (s[i]-s[j])/(double)(s[i-1]-s[j-1]);//斜率
}
int main()
{
	n=read();m=read();
	for(int i=1;i<=n;++i) s[i]=s[i-1]+read();
	for(int i=1;i<=m;++i) F[i]=read();
	for(int i=1;i<=n;++i)
	{
		for(;t>1&&slp(i,q[t])>slp(q[t],q[t-1]);--t);//维护一个斜率单调递减的上凸壳
		q[++t]=i;//放入队尾
	}
	f[1]=0;
	for(int i=2,l,r,mid;i<=m;++i)
	{
		l=0; r=t; 
		for(double k=F[i]/(double)F[i-1];l<r;)//二分找到最优决策点
		{
			mid=l+r>>1;
			if(slp(q[mid+1],q[mid])>k) l=mid+1; else r=mid;
		}
		f[i]=f[i-1]+s[q[l]]*F[i-1]-s[q[l]-1]*F[i];//利用最优决策算出答案
	}
	printf("%lld\n",1ll*f[m]+s[n]*F[m]);
}

猜你喜欢

转载自blog.csdn.net/xuxiayang/article/details/89280993