1. 程式人生 > >BZOJ4827:[AH2017/HNOI2017]禮物——題解

BZOJ4827:[AH2017/HNOI2017]禮物——題解

成了 AR cst min cnblogs http 定義 -- isdigit

https://www.lydsy.com/JudgeOnline/problem.php?id=4827

https://www.luogu.org/problemnew/show/P3723

題面見原題。

參考了洛谷一些題解。

先推式子,x數組為a,y數組為b,將b數組倍長後有:

技術分享圖片

因為c的範圍在[-m,m]之間,而m=100,且稍加思考後發現k在1,3,4項中是無用的,所以通過枚舉c取得1,3,4項和的最小值。

考慮計算第二項,其實是卷積型,實際上將a數組前移並倒轉即可得到:

技術分享圖片

變成了卷積,FFT即可O(nlogn),本題結束。

(PS:防止我以後看不懂寫點東西)

(從n-1枚舉到FFT的長度,在之間取得最大值即可)

(至於為什麽k可以被忽略,是因為當長度大於n-1時b[k]之前的項相當於乘了個0所以沒事。)

(當然我寫的時候發現答案對了就交了結果就陰差陽錯的AC了:) )

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cctype>
#include<cstdio>
#include<queue>
#include<cmath>
using namespace std;
typedef long double dl;
typedef 
long long ll; const dl pi=acos(-1.0); const int N=2e6+5; inline int read(){ int X=0,w=0;char ch=0; while(!isdigit(ch)){w|=ch==-;ch=getchar();} while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar(); return w?-X:X; } struct complex{//定義復數 dl x,y; complex(dl xx
=0.0,dl yy=0.0){ x=xx;y=yy; } complex operator +(const complex &b)const{ return complex(x+b.x,y+b.y); } complex operator -(const complex &b)const{ return complex(x-b.x,y-b.y); } complex operator *(const complex &b)const{ return complex(x*b.x-y*b.y,x*b.y+y*b.x); } }; void FFT(complex a[],int n,int on){ for(int i=1,j=n>>1;i<n-1;i++){ if(i<j)swap(a[i],a[j]); int k=n>>1; while(j>=k){j-=k;k>>=1;} if(j<k)j+=k; } for(int i=2;i<=n;i<<=1){ complex res(cos(-on*2*pi/i),sin(-on*2*pi/i)); for(int j=0;j<n;j+=i){ complex w(1,0); for(int k=j;k<j+i/2;k++){ complex u=a[k],t=w*a[k+i/2]; a[k]=u+t; a[k+i/2]=u-t; w=w*res; } } } if(on==-1) for(int i=0;i<n;i++)a[i].x/=n; } complex a[N],b[N]; int n,m; ll t1=0,t2=0,t3=0,t4=0; inline ll suan(int c){ return (ll)n*c*c+2*(t3-t4)*c; } int main(){ n=read(),m=read(); for(int i=n-1;i>=0;i--)a[i].x=read(); for(int i=0;i<n;i++)b[i].x=read(); for(int i=0;i<n;i++){ t1+=a[i].x*a[i].x;t2+=b[i].x*b[i].x; t3+=a[i].x;t4+=b[i].x; } for(int i=n;i<2*n;i++)b[i]=b[i-n]; int k=1;while(k<n*3)k<<=1; FFT(a,k,1);FFT(b,k,1); for(int i=0;i<k;i++)a[i]=a[i]*b[i]; FFT(a,k,-1); ll maxn=0,minn=1e18; for(int i=n-1;i<k;i++)maxn=max(maxn,(ll)(a[i].x+0.5)); for(int i=-m;i<=m;i++) if(suan(i)<minn)minn=suan(i); printf("%lld\n",t1+t2-2*maxn+minn); return 0; }

+++++++++++++++++++++++++++++++++++++++++++

+本文作者:luyouqi233。               +

+歡迎訪問我的博客:http://www.cnblogs.com/luyouqi233/ +

+++++++++++++++++++++++++++++++++++++++++++

BZOJ4827:[AH2017/HNOI2017]禮物——題解