[bzoj 4827--HNOI2017]禮物

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

這道題我們可以先化一下式子,sigma(((xi+c)-yi)^2)(c可正可負,因爲如果爲負,其實就相當於給yi+c),化成了sigma(xi^2-2* xi* yi+yi*yi+c*c+2*c*xi-2*c*yi)。其中的2* xi* yi是以不同開頭來開始的,其實我們可以很快發現這東西可以用fft來求,而然後剩下的c*c+2*c*xi-2*c*yi,我們可以運用初中的數學知識O(1)快速求出最小值,但由於c要取整,所以-b/2a時要++時再算一次,–時再算一次。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<cstdlib>
using namespace std;
const int maxn=50010;
const double pi=acos(-1.0);
struct complex
{
    double r,i;
    complex(){}
    complex(double _r,double _i){r=_r,i=_i;}
    friend complex operator +(const complex &x,const complex &y){return complex(x.r+y.r,x.i+y.i);}
    friend complex operator -(const complex &x,const complex &y){return complex(x.r-y.r,x.i-y.i);}
    friend complex operator *(const complex &x,const complex &y){return complex(x.r*y.r-x.i*y.i,x.r*y.i+x.i*y.r);}
}a1[maxn*4],a2[maxn*4],b1[maxn*4],b2[maxn*4];
int n,m;
int R[maxn*4];
void fft(complex *y,int len,int on)
{
    for(int i=0;i<len;i++)if(i<R[i])swap(y[i],y[R[i]]);
    for(int i=1;i<len;i*=2)
    {
        complex wn(cos(pi/i),sin(pi*on/i));
        for(int j=0;j<len;j+=i*2)
        {
            complex w(1,0);
            for(int k=0;k<i;k++,w=w*wn)
            {
                complex u=y[j+k];
                complex v=y[j+k+i]*w;
                y[j+k]=u+v;
                y[j+k+i]=u-v;
            }
        }
    }
    if(on==-1)for(int i=0;i<len;i++)y[i].r/=len;
}
int main()
{
    double wy,ans=0.0,s=0.0;
    scanf("%d%lf",&n,&wy);n--;
    for(int i=0;i<=n;i++)
    {
        scanf("%lf",&a1[i].r),a2[n-i].r=a1[i].r;
        ans+=a1[i].r*a1[i].r;s+=a1[i].r;
    }
    for(int i=0;i<=n;i++)
    {
        scanf("%lf",&b1[i].r),b2[n-i].r=b1[i].r;
        ans+=b1[i].r*b1[i].r,s-=b1[i].r;
    }
    m=n+n;int L=0;
    for(n=1;n<=m;n*=2)L++;
    for(int i=0;i<=n;i++)R[i]=(R[i>>1]>>1)|((i&1)<<(L-1));
    fft(a1,n,1);fft(a2,n,1);fft(b1,n,1);fft(b2,n,1);
    for(int i=0;i<=n;i++)a1[i]=a1[i]*b2[i];
    for(int i=0;i<=n;i++)a2[i]=a2[i]*b1[i];
    fft(a1,n,-1);fft(a2,n,-1);
    double ss=0.0;
    for(int i=0;i<=m/2-1;i++)ss=max(ss,a1[i].r+a2[m/2-i-1].r);
    ans-=2.0*ss;
    int he;double hehe=999999999.0;
    he=-s/(m/2+1)-1;
    hehe=min(hehe,(m/2+1)*he*he+2.0*he*s);
    he++;
    hehe=min(hehe,(m/2+1)*he*he+2.0*he*s);
    he++;
    hehe=min(hehe,(m/2+1)*he*he+2.0*he*s);
    printf("%.0lf\n",hehe+ans);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章