【洛谷P3723】礼物

题目大意:给定两个序列 A、B,现可以将 A 序列的每一个元素的值增加或减少 C,求 \(\sum\limits_{i=0}^{n-1}(a_i-b_{i+k})^2\) 的最小值是多少。

题解:先不考虑环的问题,仅考虑 A 序列所有元素增加一个值 C,这将体现在最后的求和式中,即:求和式变成 \[\sum\limits_{i=0}^{n-1}(a_i-b_{i+k}+c)^2\],将这个和式进行展开,可以发现这是一个关于 C 的二次函数,最值可以直接计算。于是问题转化成了如何求\[\sum\limits_{i=0}^{n-1}a_ib_{i+k}\]的最小值。上述形式的卷积被称作循环卷积,即:b 的下标取值范围为 \([0,2n-1]\),同时下标之差是定值,将 B 倍增之后,翻转 A 即可得到卷积的形式,最后取对应系数的最大值即可。

代码如下

#include <bits/stdc++.h>
using namespace std;
const int maxn=4e5+10;
const double pi=acos(-1);

int n,m;
double a[maxn],b[maxn],sx,sy,sx2,sy2,ans,c;
struct cp{
    double x,y;
    cp(double xx=0,double yy=0):x(xx),y(yy){}
    friend cp operator+(const cp &a,const cp &b){return cp(a.x+b.x,a.y+b.y);}
    friend cp operator-(const cp &a,const cp &b){return cp(a.x-b.x,a.y-b.y);}
    friend cp operator*(const cp &a,const cp &b){return cp(a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x);}
}f[maxn],g[maxn];
int tot=1,bit,rev[maxn];

void fft(cp *t,int type){
    for(int i=0;i<tot;i++)if(i<rev[i])swap(t[i],t[rev[i]]);
    for(int mid=1;mid<tot;mid<<=1){
        cp wn(cos(pi/mid),type*sin(pi/mid));
        for(int j=0;j<tot;j+=(mid<<1)){
            cp w(1,0);
            for(int k=0;k<mid;k++,w=w*wn){
                cp x=t[j+k],y=w*t[j+mid+k];
                t[j+k]=x+y,t[j+mid+k]=x-y;
            }
        }
    }
    if(type==-1)for(int i=0;i<tot;i++)t[i].x=round(t[i].x/tot);
}

void read_and_parse(){
    scanf("%d%d",&n,&m);
    for(int i=0;i<n;i++)scanf("%lf",&a[i]),sx+=a[i],sx2+=a[i]*a[i];
    for(int i=0;i<n;i++)scanf("%lf",&b[i]),sy+=b[i],sy2+=b[i]*b[i];
    c=round((sy-sx)/n);
    ans=n*c*c+2*c*(sx-sy)+sx2+sy2;
}
void solve(){
    for(int i=0;i<n;i++)f[i].x=f[i+n].x=a[i];
    for(int i=0;i<n;i++)g[i].x=b[n-1-i];
    m=3*(n-1);
    while(tot<=m)tot<<=1,++bit;
    for(int i=0;i<tot;i++)rev[i]=(rev[i>>1]>>1)|((i&1)<<(bit-1));
    fft(f,1),fft(g,1);
    for(int i=0;i<tot;i++)f[i]=f[i]*g[i];
    fft(f,-1);
    double mx=0;
    for(int i=n-1;i<=2*n-2;i++)mx=max(mx,f[i].x);
    printf("%.0lf\n",ans-2.0*mx);
}
int main(){
    read_and_parse();
    solve();
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/wzj-xhjbk/p/10817736.html