P3723 [AH2017/HNOI2017]礼物
性质:给一个手环加 相当于给另一个手环减
由于
m
<
=
100
m<=100
m<=100 所以令增加量为
c
c
c(可正可负),
c
∈
[
−
m
,
m
]
c∈ [-m,m]
c∈[−m,m]
设 一数列为
a
a
a ,另一列旋转以后的数列为
b
b
b , 那么费用为:
∑
i
=
1
n
(
a
i
+
c
−
b
i
)
2
\sum_{i=1}^n\left(a_i+c-b_i\right)^2
∑i=1n(ai+c−bi)2
我们把第i项拿出来拆开,得到:
(
a
i
+
c
−
b
i
)
2
=
a
i
2
+
b
i
2
+
c
2
+
2
a
i
c
−
2
a
i
b
i
−
2
b
i
c
\left(a_i+c-b_i\right)^2=a_i^2+b_i^2+c^2+2a_ic-2a_ib_i-2b_ic
(ai+c−bi)2=ai2+bi2+c2+2aic−2aibi−2bic
\text{}
\text{}
那么原式变成了
∑
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
)
−
2
∑
i
=
1
n
a
i
b
i
\sum_{i=1}^na_i^2+\sum_{i=1}^nb_i^2+nc^2+2c\left(\sum_{i=1}^na_i-\sum_{i=1}^nb_i\right)-2\sum_{i=1}^na_ib_i
∑i=1nai2+∑i=1nbi2+nc2+2c(∑i=1nai−∑i=1nbi)−2∑i=1naibi
性质:无论怎么旋转,和不变
c
c
c 可以暴枚,也可以算二次函数最值
\text{}
所以只有最后一项会改变的
问题转化为求 ∑ i = 1 n a i b i \sum_{i=1}^na_ib_i ∑i=1naibi 的最大值
把数列
a
a
a 反过来,变成
∑
i
=
1
n
a
n
−
i
+
1
b
i
\sum_{i=1}^na_{n-i+1}b_i
∑i=1nan−i+1bi
\text{}
a
n
−
i
+
1
相
当
于
多
项
式
A
的
n
−
i
+
1
次
项
系
数
a_{n-i+1}相当于 多项式A \ 的 n-i+1次项系数
an−i+1相当于多项式A 的n−i+1次项系数 ,
b
i
相
当
于
多
项
式
B
的
i
次
项
系
数
b_i相当于 多项式B 的\ i \ 次 项系数
bi相当于多项式B的 i 次项系数
∑
i
=
1
n
a
n
−
i
+
1
b
i
就
是
多
项
式
卷
积
之
后
n
+
1
次
项
的
系
数
\sum_{i=1}^na_{n-i+1}b_i 就是 多项式卷积之后 n+1次项 的系数
∑i=1nan−i+1bi就是多项式卷积之后n+1次项的系数
\text{}
将数列 b b b (或者反过来后的 a a a ) 倍长 ,用 b i + k b_{i+k} bi+k表示平移了 k k k 项
那就是对于
k
∈
[
0
,
n
−
1
]
k∈[0,n-1]
k∈[0,n−1] 求
m
i
n
(
∑
i
=
1
n
a
n
−
i
+
1
b
i
+
k
)
min( \sum_{i=1}^na_{n-i+1}b_{i+k})
min(∑i=1nan−i+1bi+k)
就是求对于
k
∈
[
0
,
n
−
1
]
k∈[0,n-1]
k∈[0,n−1] 求
m
i
n
(
卷
积
后
第
n
+
k
+
1
次
项
的
系
数
)
min( 卷积后第 n+k+1 次项的系数)
min(卷积后第n+k+1次项的系数)
\text{}
\text{}
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
const double pi=acos(-1.0);
const int N=401000;
//int a[N],b[N],c[N<<1],rev[N<<3],limit;
int a[N],b[N],c[N],rev[N],limit;
struct comp{
double x,y;
comp(double xx=0,double yy=0) { x=xx;y=yy; }
friend comp operator + (const comp &a,const comp &b) { return comp(a.x+b.x , a.y+b.y); }
friend comp operator - (const comp &a,const comp &b) { return comp(a.x-b.x , a.y-b.y); }
friend comp operator * (const comp &a,const comp &b) { return comp(a.x*b.x-a.y*b.y , a.y*b.x + a.x*b.y); }
}A[N],B[N];//A[N<<3],B[N<<3];//limit最大6*N
int minn(int x,int y) { return x<y?x:y; }
void fft(comp *a,double f)
{
for(int i=0;i<limit;i++) if(i<rev[i]) swap(a[i],a[rev[i]]);
for(int mid=1;mid<limit;mid<<=1)
{
comp wn=comp(cos(pi/mid),f*sin(pi/mid));
for(int L=0,R=(mid<<1);L<limit;L+=R){
comp w=comp(1.0,0.0);
for(int k=0;k<mid;k++,w=w*wn)
{
comp A1=a[L+k],A2=w*a[L+k+mid];
a[L+k]=A1+A2;
a[L+k+mid]=A1-A2;
}
}
}
}
int main()
{
int n,m,a1=0,a2=0,b1=0,b2=0;scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&a[i]),a1+=a[i]*a[i],a2+=a[i];
for(int i=1;i<=n;i++) scanf("%d",&b[i]),b1+=b[i]*b[i],b2+=b[i];
for(int i=1;i<=n;i++) c[i]=a[n-i+1],b[i+n]=b[i];
int nn=3*n,l=0;//c:2n b:n -- limit:3n
limit=1;
while(limit<nn) limit<<=1,l++;
for(int i=1;i<limit;i++) rev[i]=(rev[i>>1]>>1)|(i&1)<<(l-1);
for(int i=0;i<limit;i++) A[i]=comp(1.0*c[i],0.0);
for(int i=0;i<limit;i++) B[i]=comp(1.0*b[i],0.0);
fft(A,1);
fft(B,1);
for(int i=0;i<limit;i++) A[i]=A[i]*B[i];
fft(A,-1);
int ans=2147483647;
for(int i=1;i<=n;i++)
for(int c=-m;c<=m;c++)
ans=minn(ans,a1+b1+n*c*c + 2*c*(a2-b2) -2*(int)(A[i+n].x/limit+0.5));
printf("%d",ans);
return 0;
}