题目:hnoi2017
这题还是比较可做,手玩一下就好了
设改变的亮度为c;
c的取值范围为-100到+100;
其中一个子串每个亮度为Xi,另一个子串为Yi
ans=∑i=1n(Xi−Yi+c)2
a
n
s
=
∑
i
=
1
n
(
X
i
−
Y
i
+
c
)
2
平方展开得
ans=∑i=1n(Xi−Yi)2+∑i=1n(Xi−Yi)∗c∗2+∑i=1nc
a
n
s
=
∑
i
=
1
n
(
X
i
−
Y
i
)
2
+
∑
i
=
1
n
(
X
i
−
Y
i
)
∗
c
∗
2
+
∑
i
=
1
n
c
很显然这一部分是个常数
∑i=1n(Xi−Yi)
∑
i
=
1
n
(
X
i
−
Y
i
)
将c在取值范围内算一遍就能求出后两项的最小值;
至于第一项,再展开
ans=∑i=1nX2i+∑i=1nY2i−∑i=1nXi∗Yi∗2
a
n
s
=
∑
i
=
1
n
X
i
2
+
∑
i
=
1
n
Y
i
2
−
∑
i
=
1
n
X
i
∗
Y
i
∗
2
前两项也是个常数,那么现在要求的就是最后一项的最值了;
可以看出能够通过fft进行优化;
将第一个子串翻转,第二个子串复制一倍放在末尾,这两个序列做一个卷积,其中就包含所有要求的值;
由于一开始的值会和一部分0进行加和,所以不用再考虑从哪里开始算,直接从头到尾取一遍最值就好
#include<iostream>
#include<algorithm>
#include<string>
#include<cstring>
#include<cstdio>
#include<cmath>
#define LL long long
#define inf 1349880437
#define random(a,b) (a+rand()%(b-a+1))
#define pi 3.141592653589793238460643383279
const int maxn=210005;
int n,m;
int nn=1,tk=0;
int a[maxn],b[maxn],c[maxn];
double abs(double x)
{
if(x<0)return -x;
return x;
}
struct com
{
double r,i;
com(){
r=i=0.0;
}
com(double x,double y){
r=x,i=y;
}
com operator +(const com &o)const{
return com(r+o.r,i+o.i);
}
com operator -(const com &o)const{
return com(r-o.r,i-o.i);
}
com operator *(const com &o)const{
return com(r*o.r-i*o.i,r*o.i+i*o.r);
}
com operator /(const double &o)const{
return com(r/o,i/o);
}
}c1[maxn],c2[maxn], omega[maxn];
void read(register int *t,int len)
{
char s;
for(register int i=0;i<len;i++)
{
s=getchar();
while(!isdigit(s))s=getchar();
t[i]=s-'0';
}
}
void swap(com &x,com &y)
{
com z=x;
x=y;
y=z;
}
void FFT(com *p)
{
for(register int i=0,j=0; i<nn; i++)
{
if(i>j)swap(p[i],p[j]);
for(register int l=nn>>1; (j^=l)<l; l>>=1);
}
for(register int l=2;l<=nn;l<<=1)
{
int mid=l/2;
for(com *t=p;t!=p+nn;t+=l)
for(register int i=0;i<mid;i++)
{
com tp=omega[nn/l*i] * t[i+mid];
t[i+mid]=t[i]-tp;
t[i]=t[i]+ tp;
}
}
}
int v1[maxn],v2[maxn];
int tot=0,v1tot=0,v2tot=0;
com f[maxn],g[maxn];
int suma=0,sumb=0;
char sb[maxn];
int ans=inf;
int tans=0;
int main()
{
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++)
{
scanf("%d",&v1[i]);
tot+=v1[i];
v1tot+=v1[i]*v1[i];
}
for(int i=0;i<n;i++)
{
scanf("%d",&v2[i]);
tot-=v2[i];
v2tot+=v2[i]*v2[i];
}
for(int i=-100;i<=100;i++)
ans=std::min(ans,tot*i*2+n*i*i);//注意这里是n倍的i*i,我一开始写错成i*i
ans+=v1tot+v2tot;
for(int i=0;i<n;i++)
f[i].r=v1[n-i-1];
for(int i=0;i<n;i++)
g[i].r=v2[i],g[i+n].r=v2[i];
while(nn<2*n-1)nn<<=1;
for(int i=0;i<nn;i++)omega[i]=com(std::cos(2.0*pi/(double)nn*(double)i),std::sin(2.0*pi/(double)nn*(double)i));
FFT(f);
FFT(g);
for(int i=0;i<nn;i++)
{
omega[i].i*=-1;
f[i]=f[i]*g[i];
}
FFT(f);
for(int i=0;i<nn;i++)
{
f[i].r/=nn;
tans=std::max(tans,(int)(f[i].r+0.5));
}
ans-=tans*2;
printf("%d\n",ans);
return 0;
}
今天打了一个fft的板子水了好多题(* _ *);