传送门

最小化

∑ i = 1 n ( a i − b i ) 2 \sum\limits_{i=1}^n(a_i-b_i)^2 i=1n(aibi)2

同时增大亮度是没有意义的,可以转化为增大一个数组的亮度,设增大了数组 a a a亮度 x x x

∑ i = 1 n ( a i − b i + x ) 2 \sum\limits_{i=1}^n(a_i-b_i+x)^2 i=1n(aibi+x)2

= ∑ i = 1 n a i + ∑ i = 1 n b i 2 + n x 2 + 2 x ∑ i = 1 n ( a i − b i ) − 2 ∑ i = 1 n a i b i =\sum\limits_{i=1}^n a_i+\sum\limits_{i=1}^nb_i^2+nx^2+2x\sum\limits_{i=1}^n(a_i-b_i)-2\sum\limits_{i=1}^na_ib_i =i=1nai+i=1nbi2+nx2+2xi=1n(aibi)2i=1naibi

假设增加的亮度一定,变化的就只有最后一项,也就是最大化 2 ∑ i = 1 n a i b i 2\sum\limits_{i=1}^na_ib_i 2i=1naibi

但是每一种对齐方式都需要计算形如

− 2 ( a 1 b x + a 2 b x + 1 . . . + a n b x − 1 ) -2(a_1b_x+a_2b_{x+1}...+a_{n}b_{x-1}) 2(a1bx+a2bx+1...+anbx1)的式子

这部分已经是 O ( n ) O(n) O(n)的了

但是如果把 a a a数组复制一份在最后面是一个长度 2 n 2n 2n的序列

把数组 b b b反转,做卷积得到的 k ∈ [ n + 1 , 2 n ] k\in[n+1,2n] k[n+1,2n]项中有

c k = ∑ i + j = = k a i b j c_k=\sum\limits_{i+j==k}a_ib_j ck=i+j==kaibj

模拟一下 k = n + 2 k=n+2 k=n+2的情况

数组 a 1   a 2   . . . a n   a 1   a 2   . . . a n a_1\ a_2\ ...a_n\ a_1\ a_2\ ...a_n a1 a2 ...an a1 a2 ...an b n   b n − 1 . . . . b 1 b_n\ b_{n-1}....b_1 bn bn1....b1卷积

c n + 2 = a 2 ∗ b 1 + a 3 ∗ b 2 + a 4 ∗ b 3 . . . a 1 ∗ b n − 1 c_{n+2}=a_2*b_1+a_3*b_2+a_4*b_3...a_1*b_{n-1} cn+2=a2b1+a3b2+a4b3...a1bn1

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int maxn = 2e6+10;
const int mod = 998244353,G=3,Gi=(mod+1)/3;
int n,m,r[maxn],a[maxn],b[maxn];
int quick(int x,int n)
{
	int ans = 1;
	for( ; n ; n>>=1,x=x*x%mod )
		if( n&1 )	ans = ans*x%mod;
	return ans; 
}
void init(int limit)
{
	for(int i=0;i<limit;i++)	r[i] = ( r[i>>1]>>1 ) | ( (i&1)?limit>>1:0 );
}
void NTT(int *a,int limit,int type )
{
	for(int i=0;i<limit;i++)
		if( i<r[i] )	swap( a[i],a[r[i]] );
	for(int mid=1;mid<limit;mid<<=1 )
	{
		int wn = quick( (type==1)?G:Gi,(mod-1)/(mid<<1));
		for(int R=mid<<1,i=0;i<limit;i+=R)
		for(int w=1,k=0;k<mid;k++,w=w*wn%mod )
		{
			int x = a[i+k], y = a[i+k+mid]*w%mod;
			a[i+k] = (x+y)%mod, a[i+k+mid] = (x-y+mod)%mod;
		}
	}
	if( type==1 )	return;
	int inv = quick(limit,mod-2);
	for(int i=0;i<limit;i++)	a[i] = a[i]*inv%mod;
}
void mul(int *a,int *b,int n,int m)
{
	int limit = 1;
	while( limit<=n+m )	limit<<=1;
	init(limit);
	for(int i=0;i<limit;i++)
	{
		if( i>n )	a[i] = 0;
		if( i>m )	b[i] = 0;
	}
	NTT(a,limit,1); NTT(b,limit,1);
	for(int i=0;i<limit;i++)	a[i] = a[i]*b[i]%mod;
	NTT(a,limit,-1);
}
int prea,preb,ajb,ans=1e9;
signed main()
{
	cin >> n >> m;
	for(int i=1;i<=n;i++)
	{
		cin >> a[i];
		a[i+n] = a[i];
	}
	for(int i=1;i<=n;i++)	{ cin >> b[i]; }
	for(int i=1;i<=n;i++)
		prea+=a[i]*a[i],preb+=b[i]*b[i],ajb+=a[i]-b[i];
	for(int l=1,r=n;r>=l;r--,l++)	swap( b[l],b[r] );
	mul(a,b,2*n,n);
	for(int i=-100;i<=100;i++)//给i加上这么多
	for(int j=n+1;j<=2*n;j++)
		ans = min( ans,prea+preb+ajb*2*i+n*i*i-2*a[j] );	
	cout << ans;
}
Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐