北京网赛 F题 hiho1388 Periodic Signal

首先式子可以化为Ai^2+Bi^2-2*Ai*Bi;显然前面两项是一个定值,那么只需要求后面的最大值即可,但是枚举是O(n^2)的时间复杂度,超时是无疑的,那么对于这种卷积的形式,可以用到FFT,但是考虑到Ai,Bi数据很大,FFT精度就不够了,那么改用NTT。把A复制一遍放到末尾,B反转,构造多项式,这样多项式乘积指数[n,2n)的系数就是各个位置的结果了。再取一个最大值即可。


#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
#define LL long long
const LL P = 50000000001507329LL;
const int G = 3;
const int maxn=260010;
LL a[maxn], b[maxn];
LL wn[25];
int n;

LL mul(LL x, LL y)
{
    return (x * y - (LL)(x / (long double)P * y + 1e-3) * P + P) % P;
}

LL qpow(LL x, LL k, LL p)
{
    LL ret = 1;
    while(k)
    {
        if(k & 1) ret = mul(ret, x);
        k >>= 1;
        x = mul(x, x);
    }
    return ret;
}

void getwn()
{
    for(int i = 1; i <= 18; ++i)
    {
        int t = 1 << i;
        wn[i] = qpow(G, (P - 1) / t, P);
    }
}

int len;
void change(LL *y)
{
    for(int i = 1, j = len / 2; i < len - 1; ++i)
    {
        if(i < j) swap(y[i], y[j]);
        int k = len / 2;
        while(j >= k) j -= k,k /= 2;
        j += k;
    }
}

void NTT(LL *y, int on)
{
    change(y);
    int id = 0;
    for(int h = 2; h <= len; h <<= 1)
    {
        ++id;
        for(int j = 0; j < len; j += h)
        {
            LL w = 1;
            for(int k = j; k < j + h/2; ++k)
            {
                LL u = y[k],t = mul(y[k+h/2], w);
                y[k] = u + t;
                if(y[k] >= P) y[k] -= P;
                y[k+h/2] = u - t + P;
                if(y[k+h/2] >= P) y[k+h/2] -= P;
                w = mul(w, wn[id]);
            }
        }
    }
    if(on == -1)
    {
        for(int i = 1; i < len/2; ++i) swap(y[i], y[len-i]);
        LL inv = qpow(len, P - 2, P);
        for(int i = 0; i < len; ++i) y[i] = mul(y[i], inv);
    }
}

void convolution(LL *a,LL *b,int n)
{
    for(len=1;len<2*n;len<<=1);
    for(int i=n;i<len;i++) a[i]=b[i]=0;
    NTT(a,1);NTT(b,1);
    for(int i=0;i<len;i++) a[i]=mul(a[i],b[i]);
    NTT(a,-1);
}

int main()
{
    int t;
    getwn();
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        LL ans=0;
        for(int i=0;i<n;i++) scanf("%lld",&a[i]),ans+=a[i]*a[i];
        for(int i=0;i<n;i++) scanf("%lld",&b[i]),ans+=b[i]*b[i];
        for(int i=n;i<2*n;i++) a[i]=a[i-n],b[i]=0;
        for(int i=0;i<n/2;i++) swap(b[i],b[n-i-1]);
        convolution(a,b,2*n);
        LL MAX=0;
        for(int i=n;i<2*n;i++) MAX=max(MAX,a[i]);
        printf("%lld\n",ans-2*MAX);
    }
    return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值