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
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 }