BZOJ 4827: [Hnoi2017]礼物 FFT_多项式_卷积

BZOJ 4827: [Hnoi2017]礼物 FFT_多项式_卷积

Code:

#include <bits/stdc++.h>
#define setIO(s) freopen(s".in","r",stdin) 
#define maxn 3100000
#define ll long long 
using namespace std;
namespace FFT
{
    #define pi 3.1415926535898 
    struct cpx
    {
        double x,y; 
        cpx(double a=0,double b=0){x=a,y=b;} 
    }; 
    cpx operator+(cpx a,cpx b) { return cpx(a.x+b.x,a.y+b.y); }
    cpx operator-(cpx a,cpx b) { return cpx(a.x-b.x,a.y-b.y); } 
    cpx operator*(cpx a,cpx b) { return cpx(a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x); }
    void FFT(cpx *a,int n,int flag)
    {
        for(int i = 0,k = 0;i < n; ++i)
        {
            if(i > k) swap(a[i],a[k]);
            for(int j = n >> 1;(k^=j)<j;j>>=1);
        }
        for(int mid=1;mid<n;mid<<=1)
        {
            cpx wn(cos(pi/mid),flag*sin(pi/mid)),x,y; 
            for(int j=0;j<n;j+=(mid<<1)) 
            {
                cpx w(1,0); 
                for(int k=0;k<mid;++k) 
                {
                    x = a[j+k],y=w*a[j+mid+k]; 
                    a[j+k]=x+y; 
                    a[j+mid+k]=x-y; 
                    w=w*wn; 
                }
            }
        }
        if(flag==-1)  for(int i=0;i<n;++i) a[i].x/=(double)n; 
    }
    cpx A[maxn],B[maxn]; 
    void mult(int *a,int *b,int len)
    {
        int m = 1;
        while(m <= len) m <<= 1; 
        for(int i = 0;i < len; ++i) A[i].x = (double)a[i]; 
        for(int i = 0;i < len; ++i) B[i].x = (double)b[i]; 
        FFT(A,m,1),FFT(B,m,1); 
        for(int i = 0;i < m; ++i) A[i] = A[i] * B[i]; // , printf("%.2f\n",A[i].x); 
        FFT(A,m,-1);  
        for(int i = 0;i < len; ++i) a[i] = (int)(A[i].x + 0.5); 
    }
}; 
int arr[maxn],brr[maxn],n,m,t; 
ll ans = 0; 
int main()
{
    // setIO("input"); 
    scanf("%d%d",&n,&m);
    for(int i = 0;i < n; ++i) scanf("%d",&arr[i]); 
    for(int i = 0;i < n; ++i) scanf("%d",&brr[i]); 
    for(int i = 0;i < n; ++i) 
    {
        ans += 1ll*arr[i]*arr[i] + 1ll*brr[i]*brr[i]; 
        t += brr[i]-arr[i]; 
    }
    int c1 = floor(t*1.0/n), c2 = ceil(t*1.0/n); 
    ans += min(1ll*c1*c1*n - 1ll*c1*2*t, 1ll*c2*c2*n - 1ll*c2*2*t);       
    reverse(&arr[0],&arr[n]);
    for(int i = n;i < 2*n;++i) brr[i]=brr[i-n]; 
    FFT::mult(brr,arr,3*n);      
    int tmp = 0;
    for(int i = 0;i < n; ++i) tmp = max(tmp,brr[i + n]) ; 
    ans -= (tmp<<1); 
    printf("%lld\n",ans); 
    return 0; 
}

  

posted @ 2019-05-28 15:01 EM-LGH 阅读( ...) 评论( ...) 编辑 收藏
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值