GDOI2016模擬8.13生產汽車

題目
如前面提到,ABC的汽車工廠有N個工人,他們在一個傳送帶上生產汽車,工人從左到右排列,編號依次爲1到N,採用流水線模式,每個人負責自己的一部分工作。
生產一臺汽車需要從1號工人開始,當1號完成他的工作後,2號就會開始工作,然後是3號,最後當N號工人完成他的工作後,整個汽車生產完畢。工人們一共需要生產M臺汽車,而且必須按照從1到M的順序去生產。
對於工人i,他完成自己的工作需要Ti的時間,而對於汽車j,組裝複雜度爲Fj。那麼工人i花在汽車j上的時間爲Ti*Fj。
當某個工人完成他的工作後,他會同時把汽車交給下一個工人,沒有任何時間上的延遲,因此,要保證下一個要接受汽車的工人必須是空閒的。爲了滿足這個要求,ABC需要爲每一臺汽車選擇一個好時機開始製造。
ABC想知道生產完所有汽車最少需要多少時間。

理順一下題意

我們可以得到答案T是由相鄰兩次生產的最小空餘時間加上最後一個生產的時間。

那麼相鄰兩次生產的最小空餘時間怎麼求呢?
我們設當前的生產爲第j個,則對於每個工人,滿足:
T+All[i-1]*Fj≥All[i]*F[j-1](All[i]爲前i個工人的效率和,也就是Ti的前綴和)

這裏大家可以嘗試着繼續變形下去,用斜率優化做,時間複雜度爲O(n)的

但這裏我想講一個新的方法:凸包+三分+隨機化

大家是不是想不到爲什麼能用凸包?

那就對了,出題人也沒想到,數據也不知道,沒有針對性的數據,凸包上的點期望是log個,直接暴力就行,但我想講個靠譜點的:

對於那條不等式,我們可以發現

T=max(All[i]*F[j-1]-All[i-1]*Fj)

是不是很像叉積啊?

由於固定的是All[i]和All[i-1],那麼我們將其變成點(All[i],All[i-1]),做個凸包,那麼T就是凸包上所有點對(F[j],F[j-1])做叉積的最大值,爲什麼是凸包上的點就行呢?
對於叉積,我們可以看做兩點與原點形成的三角形的面積的兩倍,由於點(F[j],F[j-1])在詢問時是固定的,那麼固定了一條邊,要使得三角形面積最大,則高越長,也就是找距直線OA(A爲(F[j],F[j-1]))最遠的位於直線順時針方向的點,易證:對於所有的直線,凸包上的點就可以維護所有的答案。

作圖我們可以發現,對於任意直線,凸包上的點對答案的貢獻是一個雙峯函數,通常形狀如下圖:

這裏寫圖片描述

這樣我們可以用隨機化(隨機一個切割點,使其變成單峯函數)+三分,由於卡的數據比較難出(首先,你得使峯和谷間的點儘量少,兩端的點儘量多,而且要避免凸包使得點數變少,才能使隨機分割點的期望降低,何況這是個隨機化的做法,而且對於一個詢問而言是複雜度提高了,但其他詢問有可能函數的圖像會有所改變,不能同時卡多個點,不然加個記憶化也可以),當然,實在不放心,也可以用模擬退火,數學能力較強的,也可以畫圖,想一下如何用詢問的直線平移後將其切割成上下凸殼,直接將其變成兩個單峯函數,由於一個爲負,只做一個就行了。

總的來說,各種方法的期望都是n((logn)^2)

****補充一下,剛纔打字的時候,凝視了一下貼上來的圖,發現,若將分割點得到的答案看成函數,貌似是一個單峯函數,大家可以嘗試一下三分分割點,說不定是對的,若驗證出來的(當然用人工出的數據來卡才行),可以評論分享一下,有別的不和斜率優化相關的思路也可。
貼代碼

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<ctime>
#define random(x)(rand()%x)
using namespace std;
#define N 100001
#define TIMES 28
#define PI 3.1415926535898
int n,m,L,R,len;
int f[N],a[N][2],b[N],d[N];
long long T;
long double c[N];
void init(){
    static int x,y;
    scanf("%d %d",&n,&m);
    y=0;
    for (int i=1;i<=n;i++)
        scanf("%d",&x),a[i][1]=y,a[i][0]=(y+=x);
    for (int i=1;i<=m;i++)
        scanf("%d",&f[i]);
}
long double did(long double x){
    return x<0?x+PI+PI:x;
}
bool jian(int x,int y,int x1,int y1,int x2,int y2){
    x1-=x,y1-=y,x2-=x,y2-=y;
    return (long long)x1*y2-(long long)x2*y1<=0;
}
bool cmp(int x,int y){
    return c[x]<c[y];
}
void pre(){
    static long double midx,midy;
    midx=midy=0;
    for (int i=1;i<=n;i++)
        b[i]=i,midx+=a[i][0],midy+=a[i][1];
    midx/=n,midy/=n;
    for (int i=1;i<=n;i++)
        c[i]=did(atan2((long double)a[i][1]-midy,(long double)a[i][0]-midx));
    sort(b+1,b+n+1,cmp);
    L=1,R=1;
    d[1]=b[1];
    for (int i=2;i<=n;i++){
        while (R-L>1&&jian(a[d[R-1]][0],a[d[R-1]][1],a[d[R]][0],a[d[R]][1],a[b[i]][0],a[b[i]][1]))R--;
        d[++R]=b[i];
    }
    while (R-L>2&&jian(a[d[R-1]][0],a[d[R-1]][1],a[d[R]][0],a[d[R]][1],a[d[L]][0],a[d[L]][1]))R--;
    while (R-L>2&&jian(a[d[R]][0],a[d[R]][1],a[d[L]][0],a[d[L]][1],a[d[L+1]][0],a[d[L+1]][1]))L++;
    len=R-L+1;
}
long long treed(int x){
    static int x2,y2;
    x2=f[x],y2=f[x-1];
}
long long calc(int x,int y){
    return (long long)a[d[y]][0]*f[x-1]-(long long)a[d[y]][1]*f[x];
}
long long treed(int l,int r,int x){
    static int mid1,mid2,len,L,R;
    L=l,R=r;
    while (l<=r){
        len=r-l;
        mid1=l+len/3;
        mid2=r-len/3;
        if (calc(x,mid1)<calc(x,mid2))l=mid1+1;
        else
            r=mid2-1;
    }
    if (l>R)l=R;
    if (l<L)l=L;
    while (l>L&&calc(x,l-1)>calc(x,l))l--;
    while (l<R&&calc(x,l+1)>calc(x,l))l++;
    return calc(x,l);
}
long long get(int x){
    static long long s,mid;
    s=0;
    s=max(s,(long long)f[x-1]*a[d[R]][0]-(long long)f[x]*a[d[R]][1]);
    s=max(s,(long long)f[x-1]*a[d[L]][0]-(long long)f[x]*a[d[L]][1]);
    for (int i=1;i<=TIMES;i++){
        mid=L+random(len);
        s=max(treed(L,mid,x),s),s=max(treed(mid,R,x),s);
        s=max(s,(long long)f[x-1]*a[d[mid]][0]-(long long)f[x]*a[d[mid]][1]);
    }
    return s;
}
void work(){
    T=(long long)f[m]*a[n][0];
    for (int i=2;i<=m;i++)
        T+=get(i);
}
void write(){
    printf("%lld",T);
}
int main(){
    srand((int)time(0));
    init();
    pre();
    work();
    write();
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章