[HNOI2017]禮物
題目描述
我的室友最近喜歡上了一個可愛的小女生。馬上就要到她的生日了,他決定買一對情侶手環,一個留給自己,一個送給她。每個手環上各有 n 個裝飾物,並且每個裝飾物都有一定的亮度。
但是在她生日的前一天,我的室友突然發現他好像拿錯了一個手環,而且已經沒時間去更換它了!他只能使用一種特殊的方法,將其中一個手環中所有裝飾物的亮度增加一個相同的自然數 c(即非負整數)。並且由於這個手環是一個圓,可以以任意的角度旋轉它,但是由於上面裝飾物的方向是固定的,所以手環不能翻轉。需要在經過亮度改造和旋轉之後,使得兩個手環的差異值最小。
在將兩個手環旋轉且裝飾物對齊了之後,從對齊的某個位置開始逆時針方向對裝飾物編號1,2,…,n,其中 n 為每個手環的裝飾物個數, 第 1 個手環的 i 號位置裝飾物亮度為 xi,第 2 個手環的 i 號位置裝飾物亮度為 yi,兩個手環之間的差異值為(參見輸入輸出樣例和樣例解釋):
\sum_{i=1}^{n} (x_i-y_i)^2∑?i=1?n??(x?i???y?i??)?2??
麻煩你幫他計算一下,進行調整(亮度改造和旋轉),使得兩個手環之間的差異值最小,這個最小值是多少呢?
輸入輸出格式
輸入格式:
輸入數據的第一行有兩個數n, m,代表每條手環的裝飾物的數量為n,每個裝飾物的初始亮度小於等於m。
接下來兩行,每行各有n個數,分別代表第一條手環和第二條手環上從某個位置開始逆時針方向上各裝飾物的亮度。
輸出格式:
輸出一個數,表示兩個手環能產生的最小差異值。註意在將手環改造之後,裝飾物的亮度
可以大於 m。
輸入輸出樣例
輸入樣例#1:5 6 1 2 3 4 5 6 3 3 4 5
1
說明
【樣例解釋】
需要將第一個手環的亮度增加1,第一個手環的亮度變為: 2 3 4 5 6
旋轉一下第二個手環。對於該樣例,是將第二個手環的亮度6 3 3 4 5向左循環移動一個位置,使得第二手環的最終的亮度為: 3 3 4 5 6。
此時兩個手環的亮度差異值為1
【數據範圍】
30%的數據滿足n≤500, m≤10;
70%的數據滿足n≤5000;
100%的數據滿足1≤n≤50000, 1≤m≤100, 1≤ai≤m。
題目可以轉化為求Σ(xi-yi+d)^2的最小值.yi可以轉n下.
把這個式子展開,Σxi^2+Σyi^2+n*d^2-Σ2xi*yi+Σxi*d+Σyi*d.可以發現,x,y的二次項為常量,和d有關的項為一個二次函數,剩下的就是Σxi*yi.
這個東西有n個不同的值,分別就是第二個數組轉n下.可以把第二個數組翻轉,然後就構造出了卷積,FFT後提取系數即可.
用complex時取real()然後取整要加0.5.
1 #include<set> 2 #include<map> 3 #include<queue> 4 #include<stack> 5 #include<ctime> 6 #include<cmath> 7 #include<string> 8 #include<vector> 9 #include<cstdio> 10 #include<cstdlib> 11 #include<cstring> 12 #include<iostream> 13 #include<algorithm> 14 #include<complex> 15 #define LL long long 16 #define maxn 50000*4 17 using namespace std; 18 const double pi=acos(-1); 19 typedef complex<double> C; 20 C A[maxn],B[maxn]; 21 int R[maxn],L=0,n,nn,m; 22 LL sumx=0,sumy=0,pfx=0,pfy=0; 23 void FFT(C *k,int f){ 24 for(int i=0;i<n;i++) if(i<R[i]) swap(k[i],k[R[i]]); 25 for(int i=1;i<n;i<<=1){ 26 C wn(cos(pi/i),f*sin(pi/i)); 27 for(int j=0;j<n;j+=(i<<1)){ 28 C w(1,0); 29 for(int p=0;p<i;p++,w*=wn){ 30 C x=k[j+p],y=w*k[j+p+i]; 31 k[j+p]=x+y;k[j+p+i]=x-y; 32 } 33 } 34 } 35 if(f==-1) for(int i=0;i<n;i++) k[i]/=n; 36 } 37 LL jis(LL x){return nn*x*x+2*(sumx-sumy)*x;} 38 void solve(){ 39 LL x1=(sumy-sumx)/nn; 40 LL x2=x1+1,x3=x1-1; 41 LL zx=min(jis(x1),min(jis(x2),jis(x3))); 42 LL zd=-999999; 43 for(int i=0;i<nn-1;i++) 44 zd=max(zd,(LL)(A[i].real()+0.5+A[i+nn].real())); 45 zd=max(zd,(LL)(A[nn-1].real())); 46 printf("%lld",pfx+pfy+zx-2*zd); 47 } 48 int main() 49 { 50 int x; 51 scanf("%d%d",&n,&m),nn=n; 52 n--;m=2*n; 53 for(int i=0;i<=n;i++) scanf("%d",&x),A[i]=x,sumx+=x,pfx+=x*x; 54 for(int i=n;i>=0;i--) scanf("%d",&x),B[i]=x,sumy+=x,pfy+=x*x; 55 for(n=1;n<=m;n<<=1) L++; 56 for(int i=0;i<n;i++) R[i]=(R[i>>1]>>1)|((i&1)<<(L-1)); 57 FFT(A,1);FFT(B,1); 58 for(int i=0;i<n;i++) A[i]*=B[i]; 59 FFT(A,-1); 60 solve(); 61 return 0; 62 }
[HNOI2017]禮物