• HNOI2017礼物


    礼物
    • 这估计是最水,最无脑的一道题了
    • 首先发现总和最接近时答案最小
    • 发现答案就是((sum_{i=1}^{n}a[i]^2+b[i]^2)-2*max(sum_{i=1}^{n}a[i]*b[i+j])(0<=j<=n-1))
    • 前面随便算,主要是后面那个式子,其实就是两个数列错位相乘加起来最大值
    • (b)反过来就变成(sum_{i=1}^{n}a[i]*b[n-i-j])(0<=j<=n-1)),直接就多项式卷积,FFT一算就行了。
    // luogu-judger-enable-o2
    #include<bits/stdc++.h>
    using namespace std;
    typedef int sign;
    typedef long long ll;
    #define For(i,a,b) for(register sign i=(sign)a;i<=(sign)b;++i)
    #define Fordown(i,a,b) for(register sign i=(sign)a;i>=(sign)b;--i)
    const int N=5e4+5;
    bool cmax(ll &a,ll b){return (a<b)?a=b,1:0;}
    bool cmin(ll &a,ll b){return (a>b)?a=b,1:0;}
    template<typename T>inline T read()
    {
        T f=1,ans=0;
        char ch=getchar();
        while(!isdigit(ch)&&ch!='-')ch=getchar();
        if(ch=='-')f=-1,ch=getchar();
        while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch-'0'),ch=getchar();
        return ans*f;
    }
    template<typename T>inline void write(T x,char y)
    {
        if(x==0)
        {
            putchar('0');putchar(y);
            return;
        }
        if(x<0)
        {
            putchar('-');
            x=-x;
        }
        static char wr[20];
        int top=0;
        for(;x;x/=10)wr[++top]=x%10+'0';
        while(top)putchar(wr[top--]);
        putchar(y);
    }
    void file()
    {
        #ifndef ONLINE_JUDGE
            freopen("3723.in","r",stdin);
            freopen("3723.out","w",stdout);
        #endif
    }
    struct comp
    {
        double r,v;
        comp operator + (const comp &x) const {return (comp){r+x.r,v+x.v};}
        comp operator - (const comp &x) const {return (comp){r-x.r,v-x.v};}
        comp operator * (const comp &x) const {return (comp){r*x.r-v*x.v,r*x.v+v*x.r};} 
    };
    comp a[N<<2],b[N<<2];
    int m,n,t;
    int rev[N<<2];
    int sum1,sum2;
    void input()
    {
        n=read<int>();t=read<int>();m=n-1;
        For(i,0,m)a[i].r=read<int>(),sum1+=a[i].r;
        For(i,0,m)b[m-i].r=read<int>(),sum2+=b[m-i].r;
    }
    void init()
    {
        if(sum1>sum2)swap(a,b),swap(sum1,sum2);
        int temp=(sum2-sum1)/n;
        if(sum1+(temp+1)*n-sum2<sum2-sum1-temp*n)temp++;
        For(i,0,m)a[i].r+=temp;
        m<<=1;
        int cnt=0;
        for(n=1;n<=m;n<<=1)cnt++;
        for(int i=0;i<n;i++)rev[i]=(rev[i>>1]>>1)|((i&1)*(1<<(cnt-1)));
    }
    const double pi=acos(-1.0);
    ll ans;
    void FFT(comp *p,int type)
    {
        int i,j,k,num;
        for(i=0;i<n;i++)if(i<rev[i])swap(p[i],p[rev[i]]);
        for(i=2;i<=n;i<<=1)
        {
            comp wi={cos(pi*2/i),sin(pi*2/i)*type};
            num=i>>1;
            for(j=0;j<n;j+=i)
            {
                comp x={1,0};
                for(k=0;k<num;k++,x=x*wi)
                {
                    comp u=p[j+k],v=p[j+k+num]*x;
                    p[j+k]=u+v;
                    p[j+k+num]=u-v;
                }
            }
        }
    }
    int w[N<<2];
    void work()
    {
        //For(i,0,m>>1)write((int)a[i].r,i==m/2?'
    ':' ');
        //For(i,0,m>>1)write((int)b[i].r,i==m/2?'
    ':' ');
        ll res=0;
        For(i,0,m>>1)ans+=a[i].r*a[i].r+b[i].r*b[i].r;
        FFT(a,1);FFT(b,1);
        for(int i=0;i<n;i++)a[i]=a[i]*b[i];
        FFT(a,-1);
        for(int i=0;i<n;i++)w[i]=(int)(a[i].r/n+0.5);
        m>>=1;
        For(i,0,m-1)cmax(res,w[i]+w[i+m+1]);
        write(ans-res*2,'
    ');
    }
    int main()
    {
        file();
        input();
        init();
        work();
        return 0;
    }
    
  • 相关阅读:
    zabbix邮件报警
    简单的带权随机算法
    一、向量
    C#遍历DataSet
    旅游(二)——广州
    旅游(一)——潮州
    LoRa术语
    Linux基础(一)
    Git(二)_基本命令
    Git使用(一)——Cygwin
  • 原文地址:https://www.cnblogs.com/dengyixuan/p/8361950.html
Copyright © 2020-2023  润新知