1. 程式人生 > >【刷題】BZOJ 4827 [Hnoi2017]禮物

【刷題】BZOJ 4827 [Hnoi2017]禮物

初始 CP 數值 int str AI void 數量 多少

Description

我的室友最近喜歡上了一個可愛的小女生。馬上就要到她的生日了,他決定買一對情侶手 環,一個留給自己,一個送給她。每個手環上各有 n 個裝飾物,並且每個裝飾物都有一定的亮度。但是在她生日的前一天,我的室友突然發現他好像拿錯了一個手環,而且已經沒時間去更換它了!他只能使用一種特殊的方法,將其中一個手環中所有裝飾物的亮度增加一個相同的自然數 c(即非負整數)。並且由於這個手環是一個圓,可以以任意的角度旋轉它,但是由於上面 裝飾物的方向是固定的,所以手環不能翻轉。需要在經過亮度改造和旋轉之後,使得兩個手環的差異值最小。在將兩個手環旋轉且裝飾物對齊了之後,從對齊的某個位置開始逆時針方向對裝飾物編號 1,2,…,n,其中 n 為每個手環的裝飾物個數,第 1 個手環的 i 號位置裝飾物亮度為 xi,第 2 個手 環的 i 號位置裝飾物亮度為 yi,兩個手環之間的差異值為(參見輸入輸出樣例和樣例解釋): \sum_{i=1}^{n}(x_i-y_i)^2麻煩你幫他計算一下,進行調整(亮度改造和旋轉),使得兩個手環之間的差異值最小, 這個最小值是多少呢?

Input

輸入數據的第一行有兩個數n, m,代表每條手環的裝飾物的數量為n,每個裝飾物的初始 亮度小於等於m。

接下來兩行,每行各有n個數,分別代表第一條手環和第二條手環上從某個位置開始逆時 針方向上各裝飾物的亮度。

1≤n≤50000, 1≤m≤100, 1≤ai≤m

Output

輸出一個數,表示兩個手環能產生的最小差異值。

註意在將手環改造之後,裝飾物的亮度 可以大於 m。

Sample Input

5 6
1 2 3 4 5
6 3 3 4 5

Sample Output

1
【樣例解釋】
需要將第一個手環的亮度增加1,第一個手環的亮度變為: 2 3 4 5 6 旋轉一下第二個手環。對於該樣例,是將第

二個手環的亮度6 3 3 4 5向左循環移動 2017-04-15 第 6 頁,共 6 頁 一個位置,使得第二手環的最終的亮度為
:3 3 4 5 6。 此時兩個手環的亮度差異值為1。

Solution

可以變換位置,也可以同時加數
假設確定了兩個序列的位置,那麽答案就是 \(\sum_{i=0}^{n-1}(xi-yi+c)^2\)
拆開, \(\sum_{i=0}^{n-1}x_i^2+y_i^2+c^2-2x_iy_i+2x_ic-2y_ic\)

\(~~~~(\sum_{i=0}^{n-1}x_i^2+y_i^2)+(\sum_{i=0}^{n-1}c^2+2c(x_i-y_i))-2(\sum_{i=0}^{n-1}x_iy_i)\)


\(=[(\sum_{i=0}^{n-1}x_i^2)+(\sum_{i=0}^{n-1}y_i^2)]+[nc^2+2((\sum_{i=0}^{n-1}x_i)-(\sum_{i=0}^{n-1}y_i))c]-2[\sum_{i=0}^{n-1}x_iy_i]\)

然後,第一部分就是求和,第二部分可以發現是個系數確定的二次函數,要最小肯定是取最值
也就是說,對於每一種不同的序列的排列,有兩項的值是一直不變的。那麽我們只要算第三部分,找排列使第三部分的值最小,那麽就會使最終答案最小
其實把 \(y\) 數組翻轉一下,就會發現它其實就是個FFT
假設兩個數組是這樣對應的

技術分享圖片

那麽 \(y\) 數組翻轉之後變成了這樣

技術分享圖片

變成了兩個交叉部分,而這兩個部分對應的形式不就是FFT的形式嗎
於是就枚舉兩個部分的分界點,將兩個FFT加起來就是一種對應方案的第三部分的答案
對所有方案取min就好了
註意的一點是,在求二次函數的最值的時候,因為數列同時加數必須是自然數,小數不行,那麽就不能直接用最值公式去得到最值,必須得到兩個最接近對稱軸的整數點,用它們求函數值取min

#include<bits/stdc++.h>
#define ui unsigned int
#define ll long long
#define db double
#define ld long double
#define ull unsigned long long
const int MAXN=1<<17,inf=0x3f3f3f3f;
const db Pi=acos(-1.0);
int qn,n,m,rev[MAXN],G[MAXN],ans=inf,xs,ys,xs2,ys2,cnt,x1,x2,ext;
struct Complex{
    db real,imag;
    inline Complex operator + (const Complex &A) const {
        return (Complex){real+A.real,imag+A.imag};
    };
    inline Complex operator - (const Complex &A) const {
        return (Complex){real-A.real,imag-A.imag};
    };
    inline Complex operator * (const Complex &A) const {
        return (Complex){real*A.real-imag*A.imag,imag*A.real+real*A.imag};
    };
};
Complex x[MAXN],y[MAXN];
template<typename T> inline void read(T &x)
{
    T data=0,w=1;
    char ch=0;
    while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    if(ch=='-')w=-1,ch=getchar();
    while(ch>='0'&&ch<='9')data=((T)data<<3)+((T)data<<1)+(ch^'0'),ch=getchar();
    x=data*w;
}
template<typename T> inline void write(T x,char ch='\0')
{
    if(x<0)putchar('-'),x=-x;
    if(x>9)write(x/10);
    putchar(x%10+'0');
    if(ch!='\0')putchar(ch);
}
template<typename T> inline void chkmin(T &x,T y){x=(y<x?y:x);}
template<typename T> inline void chkmax(T &x,T y){x=(y>x?y:x);}
template<typename T> inline T min(T x,T y){return x<y?x:y;}
template<typename T> inline T max(T x,T y){return x>y?x:y;}
inline void FFT(Complex *A,int tp)
{
    for(register int i=0;i<n;++i)
        if(i<rev[i])std::swap(A[i],A[rev[i]]);
    for(register int l=2;l<=n;l<<=1)
    {
        Complex wn=(Complex){cos(2*Pi/l),sin(tp*2*Pi/l)};
        for(register int i=0;i<n;i+=l)
        {
            Complex w=(Complex){1,0};
            for(register int j=0;j<(l>>1);++j)
            {
                Complex A1=A[i+j],A2=A[i+j+(l>>1)]*w;
                A[i+j]=A1+A2,A[i+j+(l>>1)]=A1-A2;
                w=w*wn;
            }
        }
    }
}
int main()
{
    read(qn);read(m);
    for(register int i=0;i<qn;++i)
    {
        int k;read(k);
        x[i].real=(db)k,xs+=k,xs2+=k*k;
    }
    for(register int i=0;i<qn;++i)
    {
        int k;read(k);
        y[qn-i-1].real=(db)k,ys+=k,ys2+=k*k;
    }
    m=qn+qn-1;
    for(n=1;n<m;n<<=1)cnt++;
    for(register int i=0;i<n;++i)rev[i]=(rev[i>>1]>>1)|((i&1)<<(cnt-1));
    FFT(x,1);FFT(y,1);
    for(register int i=0;i<n;++i)x[i]=x[i]*y[i];
    FFT(x,-1);
    for(register int i=0;i<n;++i)G[i]=(int)(x[i].real/n+0.5);
    chkmin(ans,-2*G[qn-1]);
    for(register int i=0;i<qn;++i)chkmin(ans,-2*(G[i]+G[i+qn]));
    x1=ceil((db)-(xs-ys)/qn),x2=floor((db)-(xs-ys)/qn);
    ext=min(qn*x1*x1+2*(xs-ys)*x1,qn*x2*x2+2*(xs-ys)*x2);
    write(ans+xs2+ys2+ext,'\n');
    return 0;
}

【刷題】BZOJ 4827 [Hnoi2017]禮物