LG 3723 [AH2017/HNOI2017]礼物

LG 3723 [AH2017/HNOI2017]礼物

前言

感觉这道 FFT 挺水的(((

我这种蒟蒻都能做出来,一遍写对。估计这个题是真的有点简单了

解法

我们其实很快可以观察出一个性质:

性质1

对于增加的亮度 \(c\),可以小于 \(0\)

这个太好理解了吧,就是不增加这一串的亮度,去增加另一串,不就相当于减小这一串的亮度吗?(挺绕的qwq)

性质2

对于增加的亮度 \(c\),一定满足 \(-m\leq c\leq m\)

自证不难。

这个也很容易证明。我们可以想,如果 \(|c|>m\),由于 \(\forall i\ \ a_i\leq m,b_i\leq m\),那么此时 \(c\) 一定不是最优的。

我们开始推柿子。

性质1,我们知道:

\[ans=\min\limits_{x=-m}^m \sum\limits_{i=1}^n(a_i-b_i+x)^2 \]

展开得:

\[ans=\min\limits_{x=-m}^m \sum\limits_{i=1}^n({a_i}^2+{b_i}^2-2\cdot a_i\cdot b_i+2\cdot a_i\cdot x-2\cdot x\cdot b_i+x^2) \]

略加整理得:

\[ans=\min\limits_{x=-m}^m \sum\limits_{i=1}^n({a_i}^2+{b_i}^2)+2\cdot x\cdot\sum\limits_{i=1}^n (a_i-b_i)+n\cdot x^2+2\cdot\sum\limits_{i=1}^n a_i\cdot b_i \]

如果我们枚举 \(x\),那么就只有 \(2\cdot\sum\limits_{i=1}^n a_i\cdot b_i\) 这一项是变量了,我们应该使这个部分的值最大。

这不就是经典的翻转数组 FFT 吗?我们翻转数组 \(a\),这样这个部分就变为了 \(2\cdot\sum\limits_{i=1}^n a_{n-i+1}\cdot b_i\)。用 FFT 求两个多项式的积,然后看多项式 \(n+1\)\(2\cdot n\) 次项的系数,取最大值即可。最后在 \(-m\)\(m\) 的区间里枚举 \(x\) 即可。时间复杂度 \(O(n\log n+n+2\cdot m)\)

如果你想优化亿点点时间复杂度,你可以用三分法去锁定 \(x\),把时间复杂度最后一项降低。

或者你可以利用二次函数的性质,把式子想象成一个关于 \(x\) 的二次函数,利用对称轴求最值即可。

但是你没必要在简单问题上耍杂技。除非在女同学面前qwq

代码

//Don't act like a loser.
//This code is written by huayucaiji
//You can only use the code for studying or finding mistakes
//Or,you'll be punished by Sakyamuni!!!
#include<bits/stdc++.h>
#define int long long
using namespace std;

int read() {
	char ch=getchar();
	int f=1,x=0;
	while(ch<'0'||ch>'9') {
		if(ch=='-')
			f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9') {
		x=x*10+ch-'0';
		ch=getchar();
	}
	return f*x;
}

const int MAXN=1e6+10;
const double pi=acos(-1.0);
typedef complex<double> Complex;

int n,m,d,cost,coft;//constant,coefficient
int a[MAXN],b[MAXN],r[MAXN];
Complex f[MAXN],g[MAXN];

void FFT(Complex A[],int inv) {
	for(int i=0;i<d;i++) {
		if(i<r[i]) {
			swap(A[i],A[r[i]]);
		}
	}
	
	for(int len=1;len<d;len<<=1) {
		Complex wn=Complex(cos(pi/len),inv*sin(pi/len));
		for(int i=0;i<d;i+=len*2) {
			Complex w(1,0);
			for(int k=0;k<len;k++,w*=wn) {
				Complex x=A[i+k];
				Complex y=w*A[i+k+len];
				A[i+k]=x+y;
				A[i+k+len]=x-y;
			}
		}
	}
	
	if(inv==-1) {
		for(int i=0;i<d;i++) {
			A[i]/=d;
		}
	}
}

signed main() {
	cin>>n>>m;
	for(int i=0;i<n;i++) {
		a[i]=read();
		cost+=a[i]*a[i];
		f[i]=a[i];
	}
	for(int i=0;i<n;i++) {
		b[i]=read();
		cost+=b[i]*b[i];
		coft+=a[i]-b[i];
		g[i]=b[i];
	}
	reverse(f,f+n);
	for(int i=n;i<2*n;i++) {
		f[i]=f[i-n];
	}
	
	d=1;
	int l=0;
	while(d<3*n) {
		d<<=1;
		l++;
	}
	for(int i=0;i<d;i++) {
		r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));
	}
	
	FFT(f,1);
	FFT(g,1);
	for(int i=0;i<d;i++) {
		f[i]=f[i]*g[i];
	}
	FFT(f,-1);
	
	int maxx=-1;
	for(int i=n;i<n*2;i++) {
		maxx=max(maxx,(int)(f[i].real()+0.49)*2);
	}
	int ans=1e18;
	cost-=maxx;
	
	for(int x=-m;x<=m;x++) {
		ans=min(ans,cost+n*x*x+2*x*coft);
	}
	
	cout<<ans<<endl;
	return 0;
}
原文地址:https://www.cnblogs.com/huayucaiji/p/LG3723.html