zoukankan      html  css  js  c++  java
  • [2019.2.15]BZOJ4827 [Hnoi2017]礼物

    设第一个串为(a),第二个串为(b)

    不妨让我们的所有操作对(b)进行。

    如果我们将(b)逆时针转动(j(0le j<n))个单位,那么与(a_i)对应的装饰物就是(b_{i+j})了。

    注:在本文中,数组下标从1开始。对于(b),当数组下标大于数组长度,我们将其对数组长度取余。

    我们对(b)进行了(j(0le j<n))次逆时针旋转,增加了(c(-mle cle m))的亮度,设(ans_x)表示(j=x)时的答案,那么

    (ans_j=sum_{i=1}^n(a_i-b_{i+j}-c)^2)

    (ans_j=sum_{i=1}^n[a_i^2+b_{i+j}^2-2c(a_i-b_{i+j})-2a_ib_{i+j}+c^2])

    (ans_j=sum_{i=1}^na_i^2+sum_{i=1}^nb_{i+j}^2-2c(sum_{i=1}^na_i-sum_{i=1}^nb_{i+j})+ nc^2-2sum_{i=1}^na_ib_{i+j})

    (ans_j=sum_{i=1}^na_i^2+sum_{i=1}^nb_i^2-2c(sum_{i=1}^na_i-sum_{i=1}^nb_i)+nc^2-2sum_{i=1}^na_ib_{i+j})

    发现只有最后一项与(j)有关,且该项与(c)无关。

    考虑求(sum_{i=1}^na_ib_{i+j})

    我们翻转(b)。则原式变为

    (sum_{i=1}^na_ib_{n+j-i+1})

    发现上式是卷积的形式。

    这样看不明显,但是如果我们认为当(i>n),(a_i=0),那原式等价于

    (sum_{i=1}^{n+j}a_ib_{n+j-i+1})

    就很明显了。

    所以我们设当(j=x),原式值为(v_{n+j}),那么我们可以用(FFT)求出(v),由于(v_{n+j})越大,(ans_j)越小,当(0le j<n)时,(nle n+j<2n),所以原式的最大值为(max_{i=n}^{2n-1}v_i)

    我们枚举(c),即可求得其他项的答案,。

    时间复杂度(O(nmlog n))

    code:

    注:方便进行(FFT),代码中下标从0开始。

    code:

    #include<bits/stdc++.h>
    #define VAL(x) (int)(fabs(x.re)/(N*1.0)+0.5)
    using namespace std;
    const int INF=2e9;
    const double pi=acos(-1);
    struct com{
    	double re,in;
    }f[300010],f1[300010],f2[300010],cpy[300010];
    com operator+(const com &x,const com &y){
    	return (com){x.re+y.re,x.in+y.in};
    }
    com operator-(const com &x,const com &y){
    	return (com){x.re-y.re,x.in-y.in};
    }
    com operator*(const com &x,const com &y){
    	return (com){x.re*y.re-x.in*y.in,x.re*y.in+x.in*y.re};
    }
    int n,m,N=1,a,b,a1,b1,a2,b2,mx;
    long long ans=INF;
    void FFT(com *f,int l,int len,int op){
    	if(len<2)return;
    	int nl=len>>1,tmp=l-1;
    	for(int i=l;i<l+len;++i)cpy[i]=f[i];
    	for(int i=l;i<l+nl;++i)f[i]=cpy[++tmp],f[i+nl]=cpy[++tmp];
    	FFT(f,l,nl,op),FFT(f,l+nl,nl,op);
    	com w=(com){cos(pi/(1.0*nl)),sin(pi/(1.0*nl)*op)},nw=(com){1,0},t;
    	for(int i=l;i<l+nl;++i,nw=nw*w)t=nw*f[i+nl],cpy[i]=f[i]+t,cpy[i+nl]=f[i]-t;
    	for(int i=l;i<l+len;++i)f[i]=cpy[i];
    }
    int main(){
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=n;++i)scanf("%d",&a),f1[i-1]=(com){a,0},a1+=a,a2+=a*a;//len(f1)=n
    	for(int i=1;i<=n;++i)scanf("%d",&b),f2[n-i]=f2[n-i+n]=(com){b,0},b1+=b,b2+=b*b;//len(f2)=2n
    	//len(f)=3n-1
    	while(N<3*n-1)N<<=1;
    	FFT(f1,0,N,1),FFT(f2,0,N,1);
    	for(int i=0;i<N;++i)f[i]=f1[i]*f2[i];
    	FFT(f,0,N,-1);
    	//f[x]=sum(0<=i<=x)f1[i]*f2[x-i]
    	for(int i=n-1;i<2*n-1;++i)mx=max(mx,VAL(f[i]));
    	for(int i=-m;i<=m;++i)ans=min(ans,1ll*n*i*i+2*i*(a1-b1));
    	printf("%lld",ans+a2+b2-2*mx);
    	return 0;
    }
    
  • 相关阅读:
    浏览器
    背景图片设置
    用CSS画平行四边形
    git常用操作
    函数Function
    Object类型的创建和访问
    执行环境及作用域
    传值和传引用
    String类型
    HTML< legend >标签
  • 原文地址:https://www.cnblogs.com/xryjr233/p/BZOJ4827.html
Copyright © 2011-2022 走看看