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 }

 

posted @ 2017-04-29 16:30  wfj_2048  阅读(184)  评论(0编辑  收藏  举报