[AH2017/HNOI2017]礼物
礼物
题解
多简单的一道FFT板题呀!
我们发现,增加的亮度 c c c的值为正还是为负都是没有关系的,只是对不同手环操作的问题,所以下面不会考虑 c c c的正负。
有 ∑ i = 1 n ( x i − y i + c ) 2 = ∑ i = 1 n ( x i 2 + y i 2 ) + 2 c ∑ i = 1 n ( x i − y i ) + c 2 n − 2 ∑ i = 1 n x i y i \sum_{i=1}^{n}(x_{i}-y_{i}+c)^2=\sum_{i=1}^{n}(x_{i}^2+y_{i}^2)+2c\sum_{i=1}^{n}(x_{i}-y_{i})+c^2n-2\sum_{i=1}^{n}x_{i}y_{i} ∑i=1n(xi−yi+c)2=∑i=1n(xi2+yi2)+2c∑i=1n(xi−yi)+c2n−2∑i=1nxiyi
很容易发现除了最后一个 
     
      
       
       
         − 
        
       
         2 
        
        
        
          ∑ 
         
         
         
           i 
          
         
           = 
          
         
           1 
          
         
        
          n 
         
        
        
        
          x 
         
        
          i 
         
        
        
        
          y 
         
        
          i 
         
        
       
      
        -2\sum_{i=1}^{n}x_{i}y_{i} 
       
      
    −2∑i=1nxiyi以外,其它的值都与 
     
      
       
       
         x 
        
       
      
        x 
       
      
    x与 
     
      
       
       
         y 
        
       
      
        y 
       
      
    y的顺序无关,可以直接求出来。
 前面关于 
     
      
       
       
         c 
        
       
      
        c 
       
      
    c的式子也可以直接找对称轴求出,注意精度误差,可以枚举找到的对称轴前后两个点的值,取最小的。
 可最后一个 
     
      
       
        
        
          ∑ 
         
         
         
           i 
          
         
           = 
          
         
           1 
          
         
        
          n 
         
        
        
        
          x 
         
        
          i 
         
        
        
        
          y 
         
        
          i 
         
        
       
      
        \sum_{i=1}^{n}x_{i}y_{i} 
       
      
    ∑i=1nxiyi的最大值求着就有些麻烦了。
 我们可以先将 
     
      
       
       
         x 
        
       
      
        x 
       
      
    x给倒过来,就成了 
     
      
       
        
        
          ∑ 
         
         
         
           i 
          
         
           = 
          
         
           1 
          
         
        
          n 
         
        
        
        
          a 
         
         
         
           n 
          
         
           − 
          
         
           i 
          
         
           + 
          
         
           1 
          
         
        
        
        
          y 
         
        
          i 
         
        
       
      
        \sum_{i=1}^{n}a_{n-i+1}y_{i} 
       
      
    ∑i=1nan−i+1yi,此时两者的和是一定的,可以转化成多项式,将 
     
      
       
       
         y 
        
       
      
        y 
       
      
    y延长一倍,两个多项式相乘,第 
     
      
       
       
         n 
        
       
         + 
        
       
         1 
        
       
      
        n+1 
       
      
    n+1到 
     
      
       
       
         2 
        
       
         n 
        
       
      
        2n 
       
      
    2n项中系数最大的就是上式的最大值。
 注意转化成多项式后应该是从 
     
      
       
        
        
          x 
         
        
          0 
         
        
       
      
        x^0 
       
      
    x0开始的,不是 
     
      
       
        
        
          x 
         
        
          1 
         
        
       
      
        x^1 
       
      
    x1。
总时间复杂度 O ( n l o g n ) O\left(nlog\, n\right) O(nlogn)。
源码
#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define MAXN 300005
#define reg register
typedef long long LL;
typedef unsigned long long uLL;
typedef pair<int,int> pii;
const double PI=acos(-1.0);
template<typename _T>
_T Fabs(_T x){return x>0?x:-x;}
template<typename _T>
inline void read(_T &x){
	_T f=1;x=0;char s=getchar();
	while('0'>s||'9'<s){if(s=='-')f=-1;s=getchar();}
	while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
	x*=f;
}
int n,m,rev[MAXN],lim;LL ans,suma,sumb;
struct cp{
	double x,y;cp(double X=0,double Y=0){x=X;y=Y;}
	inline friend cp operator + (const cp &a,const cp &b){return cp(a.x+b.x,a.y+b.y);}
	inline friend cp operator - (const cp &a,const cp &b){return cp(a.x-b.x,a.y-b.y);}
	inline 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);}
}a[MAXN],b[MAXN];
inline void fft(cp *A,int typ){
	for(reg int i=0;i<lim;++i)if(i<rev[i])swap(A[i],A[rev[i]]);
	for(reg int mid=1;mid<lim;mid<<=1){
		const cp Wn(cos(PI/mid),typ*sin(PI/mid));
		for(reg int R=mid<<1,j=0;j<lim;j+=R){
			cp w(1,0);
			for(int k=0;k<mid;++k,w=w*Wn){
				cp x=A[j+k],y=w*A[j+mid+k];
				A[j+k]=x+y;A[j+mid+k]=x-y;
			}
		}
	}
}
signed main(){
	read(n);read(m);
	for(reg int i=0,x;i<n;++i)read(x),a[i].x=x,suma+=x,ans+=1ll*x*x;
	for(reg int i=0,x;i<n;++i)read(x),b[i].x=x,sumb+=x,ans+=1ll*x*x;
	LL x=(LL)((1.0*sumb-1.0*suma)/(2.0*n)+0.5),maxx=0,tmp=1ll*x*x*n+2ll*x*(suma-sumb);
	tmp=min(1ll*(x-1LL)*(x-1LL)*n+2ll*(x-1LL)*(suma-sumb),tmp);
	tmp=min(1ll*(x+1LL)*(x+1LL)*n+2ll*(x+1LL)*(suma-sumb),tmp);
	reverse(a,a+n);for(reg int i=0;i<n;++i)b[i+n]=b[i];
	int l=0;lim=1;while(lim<3*n)lim<<=1,++l;
	for(reg int i=1;i<=lim;++i)rev[i]=(rev[i>>1]>>1)|((i&1)<<l-1);
	fft(a,1);fft(b,1);for(reg int i=0;i<=lim;++i)b[i]=a[i]*b[i];fft(b,-1);	
	for(reg int i=0;i<=lim;++i)maxx=max(maxx,(LL)(b[i].x/lim+0.5));
	printf("%lld\n",ans+tmp-2ll*maxx);
	return 0;
}
 
                    
                
                
            
        
浙公网安备 33010602011771号