码迷,mamicode.com
首页 > 其他好文 > 详细

bzoj 4827 礼物

时间:2019-02-16 19:30:37      阅读:182      评论:0      收藏:0      [点我收藏+]

标签:mat   sdi   -o   main   class   ace   https   problem   www   

bzoj 4827 礼物

  • 可以看做将其中一个数列(假定为 \(a\) )都加上 \(c\) , \(c\) 可以为负数.易知这里 \(-m\leq c\leq m\).
  • 记要求的答案为 \(ans\) , 大力拆开括号可得:

\[ ans=\sum{(a_i+c-b_i)^2}\\=\sum a_i^2+\sum b_i^2+n\cdot c^2+2c\cdot (\sum a_i-\sum b_i)-2\sum a_i b_i. \]

  • 这里的 \(a,b\) 是原数列元素不变,通过旋转得到的.
  • 其中前两项是确定的,中间两项只与 \(c\) 有关,最后一项只与旋转方式有关.
  • \(c\) 的取值范围很小,可以枚举 \(c\) 求中间两项的最小值,而求最后一项的最大值,有一个做法:
  • \(a\) 翻转后重复一次,即拼接成 \(a'=a^Ra^R\),做卷积 \(a''=a'\otimes b\), 则 \(a''\)\(n+1\)\(2n\) 的项恰好对应了通过每种旋转方式后的 \(\sum a_i b_i\) ,可以通过验证得出.对这些项取一个最大值即可.
  • \(FFT\) 加速卷积过程,总时间复杂度为 \(O(nlogn)\) .
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define mp make_pair
#define pii pair<int,int>
#define max(a,b) ((a) < (b) ? b : a)
#define min(a,b) ((a) < (b) ? a : b)
inline int read()
{
    int x=0; 
    bool pos=1; 
    char ch=getchar();
    for(;!isdigit(ch);ch=getchar())
        if(ch=='-')
            pos=0;
    for(;isdigit(ch);ch=getchar())
        x=x*10+ch-'0';
    return pos?x:-x;
}
void write(int x)
{
    if(x>=10)
        write(x/10);
    putchar(x%10+'0');
}
void writeln(int x)
{
    write(x); 
    puts("");
}
struct cp{
    double x,y;
    cp(double xx=0,double yy=0){x=xx;y=yy;}
    cp operator +(const cp &b){return cp(x+b.x,y+b.y);}
    cp operator -(const cp &b){return cp(x-b.x,y-b.y);}
    cp operator *(const cp &b){return cp(x*b.x-y*b.y,x*b.y+y*b.x);}
};
const double PI=acos(-1.0);
const int MAXN=6e5+10;
cp omega[MAXN],inv[MAXN];
void init(int n)
{
    for(int i=0;i<n;++i)
        {
            omega[i]=cp(cos(2*PI*i/n),sin(2*PI*i/n));
            inv[i]=cp(omega[i].x,-omega[i].y);
        }
}
void FFT(cp *a,int n,bool invflag)
{
    int lim=0;
    while((1<<lim)<n)
        ++lim;
    for(int i=0;i<n;++i)
        {
            int t=0;
            for(int j=0;j<lim;++j)
                if((i>>j)&1)
                    t|=1<<(lim-j-1);
            if(i<t)
                swap(a[i],a[t]);
        }
    for(int l=2;l<=n;l<<=1)
        {
            int m=l>>1;
            for(cp *p=a;p!=a+n;p+=l)
                {
                    for(int i=0;i<m;++i)
                        {
                            cp t=omega[n*i/l]*p[i+m];
                            if(invflag)
                                t=inv[n*i/l]*p[i+m];
                            p[i+m]=p[i]-t;
                            p[i]=p[i]+t;
                        }
                }
        }
    if(invflag)
        {
            for(int i=0;i<n;++i)
                a[i].x/=n;
        }
}
ll suma=0,sumb=0,sqa=0,sqb=0,sdif=0,mulmax=0;
int n,m;
cp a[MAXN],b[MAXN];
int main()
{
    freopen("gift15.in","r",stdin);
    n=read(),m=read();
    for(int i=0;i<n;++i)
        {
            int x=read();
            a[i]=x;
            suma+=x;
            sqa+=x*x;
        }
    reverse(a,a+n);
    for(int i=n;i<2*n;++i)
        a[i]=a[i-n];
    for(int i=0;i<n;++i)
        {
            int x=read();
            b[i]=x;
            sumb+=x;
            sqb+=x*x;
        }
    sdif=suma-sumb;
    int N=1;
    while(N<3*n)
        N<<=1;
    init(N);
    FFT(a,N,0);
    FFT(b,N,0);
    for(int i=0;i<N;++i)
        a[i]=a[i]*b[i];
    FFT(a,N,1);
    for(int i=n;i<2*n;++i)
        mulmax=max(mulmax,(long long)(a[i].x+0.5));
    ll ans=1e18;
    for(int c=-m;c<=m;++c)
        ans=min(ans,sqa+sqb+n*c*c+2*c*sdif-2*mulmax);
    printf("%lld\n",ans);
    return 0; 
}

bzoj 4827 礼物

标签:mat   sdi   -o   main   class   ace   https   problem   www   

原文地址:https://www.cnblogs.com/jklover/p/10388828.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!