1. 程式人生 > 其它 >【數學】[AH2017/HNOI2017]禮物

【數學】[AH2017/HNOI2017]禮物

先列舉 \(c\) 打一個表,然後發現這是個關於 \(c\) 的凸函式。

int main() {
	read(n); read(m);
	for (int i=1; i<=n; i++) read(A[i]);
	for (int i=1; i<=n; i++) read(B[i]);
	for (int j=-10; j<=10; j++) {
		for (int i=1; i<=n; i++) A[i]+=j;
		int mn=inf;
		for (int k=0; k<n; k++) {
			int cnt=0;
			for (int i=1; i<=n; i++) {
				int nxt=(i+k)%n;
				if (nxt==0) nxt=n;
				cnt+=(A[nxt]-B[i])*(A[nxt]-B[i]);
			}
			mn=min(mn, cnt);
		}
		printf("%d\n", mn);
		for (int i=1; i<=n; i++) A[i]-=j;
	}
	return 0;
}

輸出的是:

628
521
424
337
260
193
136
89
52
25
8
1
4
17
40
73
116
169
232
305
388

於是考慮三分一個 \(c\),然後列舉那個移位,因為 \(c\in[-m,m]\) 所以也不需要三分。

考慮拆式子:\((a+c-b)^2=a^2+b^2+c^2+2ac-2bc-2ab\)。然後只有 \(2ab\) 不是定值,於是只用求 \(2ab\) 的最大值即可。然後我們發現是 \(\sum A_{i+k}\times B_{i}\),令 \(\bar{B_i}=B_{n-i+1}\),然後就是個卷積式,所以最後移 \(k\) 位的答案就是捲起來後 \([x^{n+k+1}]\)

,於是就做完了。

#include <bits/stdc++.h>
using namespace std;
const double eps=1e-6;
const double pi=acos(-1.0);
const int MAXN=1000005;
const int inf=1e9;
template <typename T>
void read(T &x) {
	T flag=1;
	char ch=getchar();
	for (; '0'>ch||ch>'9'; ch=getchar()) if (ch=='-') flag=-1;
	for (x=0; '0'<=ch&&ch<='9'; ch=getchar()) x=x*10+ch-'0';
	x*=flag; 
}
struct com{
	double x, y;
	com(){};
	com(double _x, double _y) { x=_x, y=_y; }
	friend com operator + (com u, com v) { return com(u.x+v.x, u.y+v.y); }
	friend com operator - (com u, com v) { return com(u.x-v.x, u.y-v.y); }
	friend com operator * (com u, com v) { return com(u.x*v.x-u.y*v.y, u.x*v.y+u.y*v.x); }
	friend com operator * (com u, double v) { return com(u.x*v, u.y*v); }
	friend com operator / (com u, double v) { return com(u.x/v, u.y/v); }
};
int n, m;
int A[100005], B[100005];
int rev[MAXN];
com F[MAXN], G[MAXN];
void fft(com*f, int n, int op) {
	int len=(1<<n);
	for (int i=0; i<len; i++) if (i<rev[i]) swap(f[i], f[rev[i]]); 
	for (int i=1; i<len; i<<=1) {
		com wn1=com(cos(1.0*pi/i), 1.0*op*sin(1.0*pi/i));
		for (int j=0; j<len; j+=(i<<1)) {
			com wnk=com(1, 0);
			for (int k=0; k<i; k++) {
				com x=f[j+k], y=f[j+k+i]*wnk;
				f[j+k]=x+y;
				f[j+k+i]=x-y;
				wnk=wnk*wn1;
			}
		}
	}
	if (op==-1) for (int i=0; i<len; i++) f[i]=f[i]/(1.0*len);
}
void poly_mul(com *f, com *g, int n, int m) {
	int len=1, lg=0;
	while (len<=n+m) len<<=1, lg++;
	for (int i=0; i<MAXN; i++) rev[i]=(rev[i>>1]>>1)|((i&1)<<(lg-1));
	fft(f, lg, 1); fft(g, lg, 1);
	for (int i=0; i<len; i++) f[i]=f[i]*g[i];
	fft(f, lg, -1);
}
int main() {
	int ans=0;
	read(n); read(m);
	int sum1=0, sum2=0;
	for (int i=1; i<=n; i++) read(A[i]), ans+=A[i]*A[i], sum1+=A[i];
	for (int i=1; i<=n; i++) read(B[i]), ans+=B[i]*B[i], sum2+=B[i];
	for (int i=1; i<=n; i++) A[i+n]=A[i];
	for (int i=1; i<=(n<<1); i++) F[i].x=A[i];
	for (int i=1; i<=(n<<1); i++) G[i].x=(i<=n?B[n-i+1]:0);
	poly_mul(F, G, n<<1, n<<1);
	int ANS=inf;
	int mx=-inf;
	for (int i=0; i<n; i++) mx=max(mx, (int)round(F[i+n+1].x));
	for (int j=-m; j<=m; j++) {
		ANS=min(ANS, ans+j*j*n+2*sum1*j-2*sum2*j-2*mx);
	}
	printf("%d", ANS);
	return 0;
}