COCI 2011/2012 CONTEST #3

来源:互联网 发布:选秀是网络词吗 编辑:程序博客网 时间:2024/06/12 20:33

题意:

一个工厂制造产品,有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]]));*/


原创粉丝点击