zoukankan      html  css  js  c++  java
  • loj2020 「HNOI2017」礼物

    所有的下标从 (0) 开始。

    考虑枚举 (C) (第一个加上负的等于第二个加上其绝对值)和第二个手链的偏移量 (p)。答案就是

    [sum_{i=0}^{n-1}(x_i+C-y_{(i+p) mod n})^2 ]

    复制一遍 (y) 数组就能去掉取模了,再展开就是

    [sum_{i=0}^{n-1}((x_i+C)^2-2(x_i+C)y_{i+p}+y_{i+p}^2) ]

    再展开就是

    [sum_{i=0}^{n-1}(x_i+C)^2-2sum_{i=0}^{n-1}x_iy_{i+p}-2Csum_{i=0}^{n-1}y_i+sum_{i=0}^{n-1}y_i^2 ]

    发现除了第二项别的都可以预处理后在枚举 (C)(O(1)) 得到,问题在于怎样快速求第二项。将 (x) 数组翻转就成了

    [sum_{i=0}^{n-1}x_{n-i-1}y_{i+p} ]

    显然 (p) 所对应的数就是 fft 后的第 (n+p-1) 项。fft 一次后枚举 (C,p) 即可。当然你也可以三分 (C)

    #include <iostream>
    #include <cstdio>
    #include <cmath>
    using namespace std;
    typedef long long ll;
    int n, m, xx[50005], yy[50005], lim=1, tmpcnt, rev[300005];
    ll ans=0x3f3f3f3f3f3f3f3f, sumxi, sumyi, sumxifang, sumyifang;
    const double PI=acos(-1.0);
    struct Complex{
    	double x, y;
    	Complex(double xx=0.0, double yy=0.0){
    		x = xx;
    		y = yy;
    	}
    	Complex operator+(const Complex &u)const{
    		return Complex(x+u.x, y+u.y);
    	}
    	Complex operator-(const Complex &u)const{
    		return Complex(x-u.x, y-u.y);
    	}
    	Complex operator*(const Complex &u)const{
    		return Complex(x*u.x-y*u.y, x*u.y+y*u.x);
    	}
    }A[300005], B[300005];
    void fft(Complex a[], int opt){
    	for(int i=0; i<lim; i++)
    		if(i<rev[i])
    			swap(a[i], a[rev[i]]);
    	for(int i=2; i<=lim; i<<=1){
    		Complex wn=Complex(cos(PI*2/i), opt*sin(PI*2/i));
    		int tmp=i>>1;
    		for(int j=0; j<lim; j+=i){
    			Complex w=Complex(1.0, 0.0);
    			for(int k=0; k<tmp; k++){
    				Complex tmp1=a[j+k], tmp2=w*a[j+k+tmp];
    				a[j+k] = tmp1 + tmp2;
    				a[j+k+tmp] = tmp1 - tmp2;
    				w = w * wn;
    			}
    		}
    	}
    	if(opt<0)
    		for(int i=0; i<lim; i++)
    			a[i].x /= lim;
    }
    int main(){
    	cin>>n>>m;
    	for(int i=0; i<n; i++){
    		scanf("%d", &xx[i]);
    		sumxi += xx[i];
    		sumxifang += xx[i] * xx[i];
    		A[n-i-1].x = xx[i];
    	}
    	for(int i=0; i<n; i++){
    		scanf("%d", &yy[i]);
    		sumyi += yy[i];
    		sumyifang += yy[i] * yy[i];
    		B[i+n].x = B[i].x = yy[i];
    	}
    	while(lim<=3*n)	lim <<= 1, tmpcnt++;
    	for(int i=0; i<lim; i++)
    		rev[i] = (rev[i>>1]>>1) | ((i&1)<<(tmpcnt-1));
    	fft(A, 1);
    	fft(B, 1);
    	for(int i=0; i<lim; i++)
    		A[i] = A[i] * B[i];
    	fft(A, -1);
    	for(int C=-m; C<=m; C++){
    		for(int p=0; p<n; p++){
    			ll tmp=(ll)(A[n+p-1].x+0.5);
    			ll test=0;
    			for(int i=0; i<n; i++)
    				test += xx[i] * yy[(i+p)%n];
    			tmp = -2 * tmp;
    			tmp += sumxifang + (ll)2 * C * sumxi + (ll)C * C * n;
    			tmp -= (ll)2 * C * sumyi;
    			tmp += sumyifang;
    			ans = min(ans, tmp);
    		}
    	}
    	cout<<ans<<endl;
    	return 0;
    }
    
  • 相关阅读:
    [写代码]处理一组lrc歌词文件
    [ubuntu]windows重装以后,恢复grub引导
    [HDOJ1878]欧拉回路
    [写代码]解析自定义数据库文件的思路
    [写代码]wordList——百词斩CLI版
    [HDOJ2544]最短路
    [HDOJ1285] 确定比赛名次
    [HDOJ1232]畅通工程
    [HDOJ2717]Catch That Cow
    jQuery实现点击开关图片切换
  • 原文地址:https://www.cnblogs.com/poorpool/p/8821163.html
Copyright © 2011-2022 走看看