题意:
一个工厂制造产品,有N个流程。第i个流程的时间系数是Ti。有M个产品要制造,第i个产品的容易程度是Fi。一个产品j,在流程i所需时间为TiFj。流程顺序不可颠倒,产品也必须按给定的顺序制作。一旦一个流程完成,就交给下一个流程。此时,下一个流程必须是空闲的,不然就会出错。问完成所有产品需要的时间。
数据满足1 ≤ N ≤ 100000,1 ≤ M ≤ 100000。
(翻译来自卓亮wc ppt)
分析题目,容易想到按顺序考虑每个产品,需要用o(n)时间与前一产品判断是否冲突并取最早时间,总复杂度为o(nm),考虑判断条件设bi为i开始时间,si为ti前缀和,我们是想满足此式:
b[j+1]-bj>=max(fj*s[k+1]-f[j+1]*sk),若想让b[j+1]尽量小,则等于右式即可,现在问题转化为求右式。
观察式子,与叉积很像,将同类式子合并则是(f[j],f[j+1])X(s[k],s[k+1]),由于(s[k],s[k+1])是静态的,所以其实是每次用向量(f[j],f[j+1])询问s点集中的叉积最大点(正叉积中最远点),我们可以预处理上凸壳,在上凸壳二分转折点(斜率最近点),即为距向量(f[j],f[j+1])最远点。
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
struct point
{
long long x,y;
}a[200000];
int n,m,t,k,st[200000];
long long s[200000],f[200000],b[200000],ans;
long long max(long long x,long long y) {return (x>y) ? x : y;}
long long cross(point e,point r) {return (e.x*r.y-e.y*r.x);}
long long search(int x,int y)
{
int l,r,mid;
long long sum=0;
point e,u;
e.x=x,e.y=y; //e.x=-x,e.y=-y; (cross(e,u)>0)
for (l=k+1,r=t;l<=r;)
{
mid=(l+r)>>1;
u.x=a[st[mid]].x-a[st[mid-1]].x;
u.y=a[st[mid]].y-a[st[mid-1]].y;
if (cross(e,u)>0) l=mid+1;else r=mid-1;
}
sum=max(max(cross(e,a[st[l-1]]),max(cross(e,a[st[l]]),cross(e,a[st[l+1]]))),sum);
return sum;
}
int check(int x,int y,int z)
{
point e,r;
e.x=a[z].x-a[x].x,e.y=a[z].y-a[x].y;
r.x=a[y].x-a[x].x,r.y=a[y].y-a[x].y;
long long pd=cross(e,r);
if (pd>=0) return 1;
return 0;
}
void init()
{
int i;
long long sum;
scanf("%d%d\n",&n,&m);
for (i=1;i<=n;i++) scanf("%d\n",&s[i]);
for (i=1;i<=m;i++) scanf("%d\n",&f[i]);
for (i=1;i<=n;i++) s[i]=s[i-1]+s[i],a[i].x=s[i-1],a[i].y=s[i];
for (st[t=1]=1,i=2;i<=n;i++) {
for (;(t>1)&&(check(st[t-1],st[t],i));t--) ;st[++t]=i; }
for (k=t,i=n-1;i>=1;i--){
for (;(t>k)&&(check(st[t-1],st[t],i));t--) ;st[++t]=i; }
for (b[1]=0,i=2;i<=m;i++)
sum=search(f[i-1],f[i]),b[i]=sum+b[i-1];
ans=b[m]+f[m]*s[n];
printf("%I64d\n",ans);
}
int main()
{
freopen("traka.in","r",stdin);
freopen("traka.out","w",stdout);
init();
return 0;
}
/* for (l=2,r=k;l<=r;)
{
mid=(l+r)>>1;
r.x=a[st[mid]].x-a[st[mid-1]].x;
r.y=a[st[mid]].y-a[st[mid-1]].y;
if (cross(e,r)<0) l=mid+1;else r=mid-1;
}
sum=max(cross(e,a[st[l-1]]),max(cross(e,a[st[l]])),cross(e,a[st[l+1]]));*/