zoukankan      html  css  js  c++  java
  • 【BZOJ4827】 [Hnoi2017]礼物

    BZOJ4827 [Hnoi2017]礼物


    Solution

    如果一串数的增加,不就等于另一串数减吗?

    那么我们可以把答案写成另一个形式:

    (ans=sum_{i=1}^n(x_i-y_i+C)^2)

    (y)可以是重新排列

    那么疯狂拆一下式子,化简之后就是:

    (ans=sum_{i=1}^nx_i^2+sum_{i=1}^ny_i^2+sum_{i=1}^nC^2+2*C*sum_{i=1}^n(x_i-y_i)-2*sum_{i=1}^nx_i*y_i​)

    如果我们枚举(C),那么现在的任务就是算出(sum_{i=1}^nx_i*y_i)的最大值,这样才能让(ans)最小.

    怎么做呢?

    如果把(y)数列翻转一下,那么就是:
    (sum_{i=1}^nx_i*y_i=sum_{i=1}^nx_i*y_{n-i})

    这个不就是卷积?

    考虑可以逆时针旋转怎么做?断环成链就好了啊.

    那么就是把(y)串翻转然后复制一遍,求一个卷积然后走人了.

    是的结束了.

    代码实现

    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    #include<math.h>
    #include<algorithm>
    #include<queue>
    #include<set>
    #include<map>
    #include<iostream>
    using namespace std;
    #define ll long long
    #define re register
    #define file(a) freopen(a".in","r",stdin);freopen(a".out","w",stdout)
    inline int gi()
    {
    	int f=1,sum=0;char ch=getchar();
    	while(ch>'9' || ch<'0'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0' && ch<='9'){sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
    	return f*sum;
    }
    const int N=1000010,Inf=1e9+10;
    const double Pi=acos(-1.0);
    int x[N],y[N],r[N],limit,n,m,Ans[N];
    struct node
    {
        double x,y;
        node operator+(const node b)const{return (node){x+b.x,y+b.y};}
        node operator-(const node b)const{return (node){x-b.x,y-b.y};}
        node operator*(const node b)const{return (node){x*b.x-y*b.y,x*b.y+y*b.x};}
    }A[N],B[N];
    void FFT(node *A,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)
        {
            node Root=(node){cos(Pi/mid),type*sin(Pi/mid)};
            for(int R=mid<<1,j=0;j<limit;j+=R)
            {
                node Mi=(node){1,0};
                for(int k=0;k<mid;k++,Mi=Mi*Root)
                {
                    node X=A[j+k],Y=Mi*A[j+mid+k];
                    A[j+k]=X+Y;
                    A[j+mid+k]=X-Y;
                }
            }
        }
    }
    void init()
    {
    	limit=1;int l=0;
    	for(int i=0;i<n;i++)A[i].x=x[i+1];
    	for(int i=0;i<n;i++)B[i].x=y[n-i];
    	for(int i=0;i<n;i++)B[i+n]=B[i];
    	int M=n+n-1,N=n-1;
    	while(limit<=(N+M))limit<<=1,l++;
    	for(int i=0;i<limit;i++)
    		r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));
    	FFT(A,1);FFT(B,1);
    	for(int i=0;i<limit;i++)A[i]=A[i]*B[i];
    	FFT(A,-1);
    	for(int i=0;i<limit;i++)
    		Ans[i]=(int)(A[i].x/limit+0.5);
    }
    int main()
    {
    	n=gi();m=gi();
    	for(int i=1;i<=n;i++)x[i]=gi();
    	for(int i=1;i<=n;i++)y[i]=gi();
    	int pf1=0,pf2=0,sum1=0,sum2=0,ans=Inf;
    	for(int i=1;i<=n;i++)pf1=pf1+x[i]*x[i];
    	for(int i=1;i<=n;i++)pf2=pf2+y[i]*y[i];
    	for(int i=1;i<=n;i++)sum1+=x[i];
    	for(int i=1;i<=n;i++)sum2+=y[i];
    	init();int Max=-Inf;
    	for(int i=n-1;i<n+n;i++)Max=max(Max,Ans[i]);
    	for(int C=-m;C<=m;C++)
    	{
    		int tot=pf1+pf2+C*C*n-2*Max+2*(sum1-sum2)*C;
    		ans=min(ans,tot);
    	}
    	printf("%d
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    随机生成30道四则运算题目
    《构建之法》阅读笔记01
    第一周学习进度
    个人介绍
    MyBatis(登录)
    MyBatis
    动态网页
    网页基本标签
    Servlet基础
    JSP数据交互
  • 原文地址:https://www.cnblogs.com/mleautomaton/p/10333135.html
Copyright © 2011-2022 走看看