首页 > 代码库 > bzoj4827 [Hnoi2017]礼物

bzoj4827 [Hnoi2017]礼物

Description

我的室友最近喜欢上了一个可爱的小女生。马上就要到她的生日了,他决定买一对情侣手 环,一个留给自己,一个送给她。每个手环上各有 n 个装饰物,并且每个装饰物都有一定的亮度。但是在她生日的前一天,我的室友突然发现他好像拿错了一个手环,而且已经没时间去更换它了!他只能使用一种特殊的方法,将其中一个手环中所有装饰物的亮度增加一个相同的自然数 c(即非负整数)。并且由于这个手环是一个圆,可以以任意的角度旋转它,但是由于上面 装饰物的方向是固定的,所以手环不能翻转。需要在经过亮度改造和旋转之后,使得两个手环的差异值最小。在将两个手环旋转且装饰物对齐了之后,从对齐的某个位置开始逆时针方向对装饰物编号 1,2,…,n,其中 n 为每个手环的装饰物个数,第 1 个手环的 i 号位置装饰物亮度为 xi,第 2 个手 环的 i 号位置装饰物亮度为 yi,两个手环之间的差异值为(参见输入输出样例和样例解释): \sum_{i=1}^{n}(x_i-y_i)^2麻烦你帮他计算一下,进行调整(亮度改造和旋转),使得两个手环之间的差异值最小, 这个最小值是多少呢?

Input

输入数据的第一行有两个数n, m,代表每条手环的装饰物的数量为n,每个装饰物的初始 亮度小于等于m。
接下来两行,每行各有n个数,分别代表第一条手环和第二条手环上从某个位置开始逆时 针方向上各装饰物的亮度。
1≤n≤50000, 1≤m≤100, 1≤ai≤m

Output

输出一个数,表示两个手环能产生的最小差异值。
注意在将手环改造之后,装饰物的亮度 可以大于 m。

Sample Input

5 6
1 2 3 4 5
6 3 3 4 5

Sample Output

1
【样例解释】
需要将第一个手环的亮度增加1,第一个手环的亮度变为: 2 3 4 5 6 旋转一下第二个手环。对于该样例,是将第二个手环的亮度6 3 3 4 5向左循环移动 2017-04-15 第 6 页,共 6 页 一个位置,使得第二手环的最终的亮度为:3 3 4 5 6。 此时两个手环的亮度差异值为1。

 

正解:$FFT$。

考场上切了这题,还是很高兴的。。

首先我们可以发现,一个手环最多$+m$,我们只要分别枚举每个手环加多少就行了。

我们只考虑$x$手环加数,因为$y$手环与$x$手环其实是一样的。

枚举$m$,那么$Ans=\sum_{i=1}^{n}(x_{i}+m-y_{i})^{2}$。我们把它拆开以后可以发现,$Ans=\sum_{i=1}^{n}(x_{i}+m)^{2}+y_{i}^{2}-2*y_{i}*x_{i}-2*y_{i}*m$。

容易发现,$2*x_{i}*y_{i}$是复杂度的瓶颈。其实这一项可以很容易看出是一个卷积,我们把另一个数组翻转一下,就能发现$\sum_{i=1}^{n}x_{i}*y_{i}$是一个卷积的形式,然后直接上$FFT$就能过了。

其实这题还有复杂度更优的$O(nlogn+n)$的做法,似乎是用二次函数的最值??不过$O(nlogn+nm)$也能过。。

 

  1 #include <algorithm>  2 #include <iostream>  3 #include <complex>  4 #include <cstring>  5 #include <cstdio>  6 #include <cmath>  7 #include <set>  8 #define inf (2147483647)  9 #define N (100010) 10 #define il inline 11 #define RG register 12 #define ll long long 13 #define C complex <long double> 14  15 using namespace std; 16  17 const long double pi=acos(-1.0); 18  19 int a[N],b[N],n,m; 20  21 il int gi(){ 22   RG int x=0,q=1; RG char ch=getchar(); 23   while ((ch<0 || ch>9) && ch!=-) ch=getchar(); 24   if (ch==-) q=-1,ch=getchar(); 25   while (ch>=0 && ch<=9) x=x*10+ch-48,ch=getchar(); 26   return q*x; 27 } 28  29 namespace brute{ 30  31   int ans,res1,res2; 32    33   il void work(){ 34     ans=inf; 35     for (RG int i=1;i<=n;++i) a[i]=gi(),a[n+i]=a[i],res1+=a[i]*a[i]; 36     for (RG int i=1;i<=n;++i) b[i]=gi(),b[n+i]=b[i],res2+=b[i]*b[i]; 37     for (RG int k=0;k<=m;++k){ 38       for (RG int i=1;i<=n;++i) a[i]+=k; 39       for (RG int i=1;i<=n;++i){ 40     RG int res=0; 41     for (RG int j=1;j<=n;++j) res+=(a[j]-b[i+j-1])*(a[j]-b[i+j-1]); 42     ans=min(ans,res); 43       } 44       for (RG int i=1;i<=n;++i) a[i]-=k; 45     } 46     for (RG int k=0;k<=m;++k){ 47       for (RG int i=1;i<=n;++i) b[i]+=k; 48       for (RG int i=1;i<=n;++i){ 49     RG int res=0; 50     for (RG int j=1;j<=n;++j) res+=(b[j]-a[i+j-1])*(b[j]-a[i+j-1]); 51     ans=min(ans,res); 52       } 53       for (RG int i=1;i<=n;++i) b[i]-=k; 54     } 55     printf("%d\n",ans); return; 56   } 57    58 } 59  60 namespace cheat{ 61    62   C A[4*N],B[4*N]; 63   int rev[4*N],NN,lg; 64   ll r1[N],r2[N],res1,res2,tot1,tot2,ans; 65    66   il void fft(C *a,RG int n,RG int f){ 67     for (RG int i=0;i<n;++i) if (i<rev[i]) swap(a[i],a[rev[i]]); 68     for (RG int i=1;i<n;i<<=1){ 69       C wn(cos(pi/i),sin(f*pi/i)),x,y; 70       for (RG int j=0;j<n;j+=(i<<1)){ 71     C w(1,0); 72     for (RG int k=0;k<i;++k,w*=wn){ 73       x=a[j+k],y=w*a[j+k+i]; 74       a[j+k]=x+y,a[j+k+i]=x-y; 75     } 76       } 77     } 78     return; 79   } 80    81   il void work(){ 82     for (RG int i=1;i<=n;++i){ 83       a[i]=gi(),A[i]=a[i]; 84       res1+=a[i]*a[i],tot1+=a[i]; 85     } 86     for (RG int i=1;i<=n;++i){ 87       b[i]=gi(),B[n-i+1]=b[i]; 88       res2+=b[i]*b[i],tot2+=b[i]; 89     } 90     for (NN=1;NN<=(n<<1);NN<<=1) lg++; ans=1LL<<60; 91     for (RG int i=0;i<NN;++i) rev[i]=rev[i>>1]>>1|((i&1)<<(lg-1)); 92     fft(A,NN,1),fft(B,NN,1); 93     for (RG int i=0;i<NN;++i) A[i]*=B[i]; fft(A,NN,-1); 94     for (RG int i=n+1;i<=(n<<1);++i){ 95       r1[i-n]=(ll)(A[i].real()/NN+0.5); 96       r1[i-n]+=(ll)(A[i-n].real()/NN+0.5); 97     } 98     memset(A,0,sizeof(A)),memset(B,0,sizeof(B)); 99     for (RG int i=1;i<=n;++i) A[n-i+1]=a[i],B[i]=b[i];100     fft(A,NN,1),fft(B,NN,1);101     for (RG int i=0;i<NN;++i) B[i]*=A[i]; fft(B,NN,-1);102     for (RG int i=n+1;i<=(n<<1);++i){103       r2[i-n]=(ll)(B[i].real()/NN+0.5);104       r2[i-n]+=(ll)(B[i-n].real()/NN+0.5);105     }106     for (RG ll k=0;k<=m;++k){107       RG ll cnt=res2;108       for (RG int i=1;i<=n;++i) cnt+=(a[i]+k)*(a[i]+k);109       for (RG int i=1;i<=n;++i) ans=min(ans,cnt-2*(r1[i]+tot2*k));110     }111     for (RG ll k=0;k<=m;++k){112       RG ll cnt=res1;113       for (RG int i=1;i<=n;++i) cnt+=(b[i]+k)*(b[i]+k);114       for (RG int i=1;i<=n;++i) ans=min(ans,cnt-2*(r2[i]+tot1*k));115     }116     printf("%lld\n",ans); return;117   }118   119 }120 121 il void work(){  122   n=gi(),m=gi();123   if (n<=500 && m<=10){ brute::work(); return; }124   cheat::work(); return;125 }126 127 int main(){128   freopen("gift.in","r",stdin);129   freopen("gift.out","w",stdout);130   work();131   return 0;132 }

 

bzoj4827 [Hnoi2017]礼物