[AHOI2017/HNOI2017][bzoj4827] 禮物 [FFT]


題面

傳送門

思路

首先,有一個結論:兩個手環增加非負整數亮度,等於其中一個增加一個整數亮度(可以為負)

我們令增加量為$x$,旋轉以后的原數列為${a}{b}$那么現在的費用就是:

$\sum_{i=1}n\left(a_i+x-b_i\right)2$

我們把第i項拿出來拆開,得到:

$\left(a_i+x-b_i\right)2=a_i2+b_i2+x2+2a_ix-2a_ib_i-2b_ix$

那么原式變成了

$\sum_{i=1}na_i2+\sum_{i=1}nb_i2+nx2+2x\left(\sum_{i=1}na_i-\sum_{i=1}nb_i\right)-2\sum_{i=1}na_ib_i$

我們發現,這個式子除了最后一項之外都是確定的QwQ

那么我們只要令最后一項最大,那么就可以得到最小的費用值了

現在問題轉化為求$\sum_{i=1}^na_ib_i$的最大值

等等,這個形式......

我們把數列${a}$反過來,變成

$\sum_{i=1}^na_{n-i+1}b_i$

這不是一個卷積嗎~

所以把反過來的數列${a}$倍長,和數列${b}$卷積,得到的項里面的第n+1到n*2項的最大值,就是$\sum_{i=1}^na_ib_i$的最大值

然后把前面的不變項加上,就是答案了

Code:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define ll long long
#define inf 1e15
using namespace std;
inline int read(){
    int re=0,flag=1;char ch=getchar();
    while(ch>'9'||ch<'0'){
        if(ch=='-') flag=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9') re=(re<<1)+(re<<3)+ch-'0',ch=getchar();
    return re*flag;
}
struct complex{
    double x,y;
    complex(double xx=0,double yy=0){x=xx;y=yy;}
    complex operator +(const complex &b){return complex(x+b.x,y+b.y);}
    complex operator -(const complex &b){return complex(x-b.x,y-b.y);}
    complex operator *(const complex &b){return complex(x*b.x-y*b.y,x*b.y+y*b.x);}
}A[400010],B[400010];
const double pi=acos(-1.0);
int n,m,limit=1,cnt=0,r[400010];
void fft(complex *a,double type){
    int i,j,mid,k;complex x,y,w,wn;
    for(i=0;i<limit;i++) if(i<r[i]) swap(a[i],a[r[i]]);
    for(mid=1;mid<limit;mid<<=1){
        wn=complex(cos(pi/mid),type*sin(pi/mid));
        for(j=0;j<limit;j+=(mid<<1)){
            w=complex(1,0);
            for(k=0;k<mid;k++,w=w*wn){
                x=a[j+k];y=w*a[j+k+mid];
                a[j+k]=x+y;a[j+k+mid]=x-y;
            }
        }
    }
}
ll a1=0,a2=0,b1=0,b2=0,ans=inf;
int a[100010],b[100010];
int main(){
    ll i,j;
    n=read();m=read();
    for(i=1;i<=n;i++){
        a[i]=read();
        a1+=a[i]*a[i];a2+=a[i];
    }
    for(i=1;i<=n;i++){
        b[i]=read();
        b1+=b[i]*b[i];b2+=b[i];
    }
    for(i=1;i<=n;i++){
        A[i].x=A[i+n].x=a[i];
        B[i].x=b[n-i+1];
    }
    
    while(limit<=(n*3)) limit<<=1,cnt++;
    for(i=0;i<limit;i++) r[i]=((r[i>>1]>>1)|((i&1)<<(cnt-1)));
    
    fft(A,1);fft(B,1);
    for(i=0;i<=limit;i++) A[i]=A[i]*B[i];
    fft(A,-1);
    for(i=0;i<=limit;i++) A[i].x=(ll)(A[i].x/limit+0.5);
    
    for(i=1;i<=n;i++){
        for(j=-m;j<=m;j++){
            ans=min(ans,a1+b1+j*j*n+2ll*j*(a2-b2)-2ll*(ll)A[i+n].x);
        }
    }
    printf("%lld",ans);
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM