背景:
最近一直在补坑。
题意:
有两个序列
a
,
b
a,b
a,b(围成两个圈),将
a
a
a序列所有的值加上一个非负整数
c
c
c(自己给的),将
b
b
b序列逆时针旋转一定的角度,求
∑
i
=
1
n
(
a
i
−
b
i
)
2
\sum\limits_{i=1}^{n}(a_i-b_i)^2
i=1∑n(ai−bi)2的最小值。
思路:
不妨假设旋转完的
b
b
b序列为
b
′
b'
b′。,则题目就是求
∑
i
=
1
n
(
a
i
+
c
−
b
i
′
)
2
\sum\limits_{i=1}^{n}(a_i+c-b'_i)^2
i=1∑n(ai+c−bi′)2的最小值。
考虑化简式子。
∑
i
=
1
n
(
a
i
+
c
−
b
i
′
)
2
\sum\limits_{i=1}^{n}(a_i+c-b'_i)^2
i=1∑n(ai+c−bi′)2
拆括号,得:
∑
i
=
1
n
(
a
i
2
+
c
2
+
b
i
′
2
+
2
∗
a
i
∗
c
−
2
∗
a
i
∗
b
i
′
−
2
∗
c
∗
b
i
′
)
\sum\limits_{i=1}^{n}(a_i^2+c^2+{b'_i}^2+2*a_i*c-2*a_i*b'_i-2*c*b'_i)
i=1∑n(ai2+c2+bi′2+2∗ai∗c−2∗ai∗bi′−2∗c∗bi′)
发现
a
i
2
+
b
i
′
2
a_i^2+{b'_i}^2
ai2+bi′2为定值,将其提出。
∑
i
=
1
n
(
a
i
2
+
b
i
′
2
)
+
∑
i
=
1
n
(
c
2
+
2
∗
a
i
∗
c
−
2
∗
a
i
∗
b
i
′
−
2
∗
c
∗
b
i
′
)
\sum\limits_{i=1}^{n}(a_i^2+{b'_i}^2)+\sum\limits_{i=1}^{n}(c^2+2*a_i*c-2*a_i*b'_i-2*c*b'_i)
i=1∑n(ai2+bi′2)+i=1∑n(c2+2∗ai∗c−2∗ai∗bi′−2∗c∗bi′)
再提取一个
2
∗
c
2*c
2∗c得:
∑
i
=
1
n
(
a
i
2
+
b
i
′
2
)
+
∑
i
=
1
n
(
c
2
+
2
∗
c
∗
(
a
i
−
b
i
′
)
)
−
∑
i
=
1
n
(
2
∗
a
i
∗
b
i
′
)
\sum\limits_{i=1}^{n}(a_i^2+{b'_i}^2)+\sum\limits_{i=1}^{n}(c^2+2*c*(a_i-b'_i))-\sum\limits_{i=1}^{n}(2*a_i*b'_i)
i=1∑n(ai2+bi′2)+i=1∑n(c2+2∗c∗(ai−bi′))−i=1∑n(2∗ai∗bi′)
提取出一些数,得到:
∑
i
=
1
n
(
a
i
2
)
+
∑
i
=
1
n
(
b
i
′
2
)
+
n
∗
c
2
+
2
∗
c
∗
(
∑
i
=
1
n
a
i
−
∑
i
=
1
n
b
i
′
)
−
∑
i
=
1
n
(
2
∗
a
i
∗
b
i
′
)
\sum\limits_{i=1}^{n}(a_i^2)+\sum\limits_{i=1}^{n}({b'_i}^2)+n*c^2+2*c*(\sum\limits_{i=1}^{n}a_i-\sum\limits_{i=1}^{n}b'_i)-\sum\limits_{i=1}^{n}(2*a_i*b'_i)
i=1∑n(ai2)+i=1∑n(bi′2)+n∗c2+2∗c∗(i=1∑nai−i=1∑nbi′)−i=1∑n(2∗ai∗bi′)
c
c
c的问题比较容易搞定,因为它与最后一个因式无关。那么发现只有
−
∑
i
=
1
n
(
2
∗
a
i
∗
b
i
′
)
-\sum\limits_{i=1}^{n}(2*a_i*b'_i)
−i=1∑n(2∗ai∗bi′)为不定值,使
−
∑
i
=
1
n
(
2
∗
a
i
∗
b
i
′
)
-\sum\limits_{i=1}^{n}(2*a_i*b'_i)
−i=1∑n(2∗ai∗bi′)的值最小即可。
考虑构造 b ′ b' b′使得其最小,不妨使 a i ′ a'_i ai′为原 a a a序列及其反向倍长序列。那么再使 b ′ ′ b'' b′′为 b b b的反向序列,此时形成了一个卷积的形式,那么答案一定就为可取的数中的最大值(前面有一个 − - −号)。
最后再套入上式求解即可。
代码:
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define LL long long
using namespace std;
const double pai=acos(-1.0);
struct comp
{
double x,y;
comp(double xx=0,double yy=0):x(xx),y(yy) {}
friend comp operator+(const comp &x,const comp &y) {return comp(x.x+y.x,x.y+y.y);}
friend comp operator-(const comp &x,const comp &y) {return comp(x.x-y.x,x.y-y.y);}
friend comp operator*(const comp &a,const comp &b) {return comp(a.x*b.x-a.y*b.y,a.x*b.y+b.x*a.y);}
}a[500000],b[500000];
int n,m,limit=1,l=0;
int r[500000];
LL as1=0,as2=0,bs1=0,bs2=0,ans=2147483647;
void FFT(comp *now,int ty)
{
for(int i=0;i<limit;i++)
if(i<r[i]) swap(now[i],now[r[i]]);
for(int mid=1;mid<limit;mid<<=1)
{
comp wn(cos(pai/mid),ty*sin(pai/mid));
for(int j=0,R=(mid<<1);j<limit;j+=R)
{
comp w(1,0);
for(int k=0;k<mid;k++,w=w*wn)
{
comp x=now[j+k],y=w*now[j+k+mid];
now[j+k]=x+y;
now[j+k+mid]=x-y;
}
}
}
}
int d1[50010],d2[50010];
int main()
{
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%d",&d1[i]);
as1+=(LL)d1[i];
as2+=(LL)d1[i]*d1[i];
}
for(int i=1;i<=n;i++)
{
scanf("%d",&d2[i]);
bs1+=(LL)d2[i];
bs2+=(LL)d2[i]*d2[i];
}
while(limit<=(n*3))
limit<<=1,l++;
for(int i=1;i<=limit;i++)
r[i]=((r[i>>1]>>1)|((i&1)<<(l-1)));
for(int i=1;i<=n;i++)
{
a[i].x=a[i+n].x=(double)d1[i];
b[i].x=(double)d2[n-i+1];
}
FFT(a,1);
FFT(b,1);
for(int i=0;i<=limit;i++)
a[i]=a[i]*b[i];
FFT(a,-1);
for(int i=1;i<=n;i++)
for(int j=-m;j<=m;j++)
ans=min(ans,as2+bs2+j*j*n+(LL)2*j*(as1-bs1)-(LL)2*(LL)(a[i+n].x/limit+0.5));
printf("%lld",ans);
}