• 【数学】[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
    ", 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),然后枚举那个移位,因为 (cin[-m,m]) 所以也不需要三分。

    考虑拆式子:((a+c-b)^2=a^2+b^2+c^2+2ac-2bc-2ab)。然后只有 (2ab) 不是定值,于是只用求 (2ab) 的最大值即可。然后我们发现是 (sum A_{i+k} imes B_{i}),令 (ar{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;
    }
    
  • 相关阅读:
    Go语言实现:【剑指offer】跳台阶
    Go语言实现:【剑指offer】斐波那契数列
    Go语言实现:【剑指offer】栈的压入、弹出序列
    Go语言实现:【剑指offer】替换空格
    Go语言实现:【剑指offer】表示数值的字符串
    Go语言实现:【剑指offer】第一个只出现一次的字符位置
    Go语言实现:【剑指offer】把字符串转换成整数
    Go语言实现:【剑指offer】翻转单词顺序列
    robot framework使用小结(二)
    robot framework使用小结(一)
  • 原文地址:https://www.cnblogs.com/zcr-blog/p/14887624.html
Copyright © 2020-2023  润新知