[2016北京集训试题15]项链-[FFT]

Description

Solution

设y[i+k]=y[i]+n。

由于我们要最优解,则假如将x[i]和y[σ[i]]连线的话,线是一定不会交叉的。

所以,$ans=\sum (x_{i}-y_{i+s}+c)^{2}$

拆开得$ans=\sum (x_{i}^{2}+y_{i+s}^{2}+c^{2}-2x_{i}y_{i+s}+2x_{i}c-2y_{i+s}c)$

其中,$x_{i}y_{i+s}$是卷积形式。

我们把经过处理的y数组reverse一下,和x数组进行卷积(这里用ntt似乎会爆常数,fft大法好)。然后针对不同的s,得到以c为未知数的所有常数或系数,ans就是一个二次函数了。c用公式解就可以。

Code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
const double pi=acos(-1);
struct C
{
    double r,i;
    friend C operator+(C a,C b){return C{a.r+b.r,a.i+b.i};}
    friend C operator*(C a,C b){return C{a.r*b.r-a.i*b.i,a.i*b.r+a.r*b.i};}
    friend C operator-(C a,C b){return C{a.r-b.r,a.i-b.i};}
}fx[100010],fy[100010];
int rev[100010];
void fft(C *num,int n,int dft)
{
    for (int i=1;i<n;i++)
        if (i<rev[i]) swap(num[i],num[rev[i]]);
    for (int step=1;step<n;step<<=1)
    {
        C wn{cos(pi/step),sin(pi/step)*dft};
        for (int j=0;j<n;j+=step*2)//从0开始!
        {
            C w{1,0};
            for (int k=0;k<step;k++,w=w*wn)
            {
                C x=num[j+k],y=w*num[j+k+step];
                num[j+k]=x+y;
                num[j+k+step]=x-y;
            }
        }
    }
    if (dft==-1) for (int i=0;i<n;i++) num[i].r/=n;
}
int T,n,k,len,L;
int x[4010],y[8010];
ll sumx[8010],sumy[8010],sumx2[8010],sumy2[8010];
int main()
{
    scanf("%d",&T);
    while (T--)
    {
        scanf("%d%d",&n,&k);
        memset(sumx,0,sizeof(sumx));
        memset(sumy,0,sizeof(sumy));
        memset(sumx2,0,sizeof(sumx2));
        memset(sumy2,0,sizeof(sumy2));
        memset(fx,0,sizeof(fx));memset(fy,0,sizeof(fy));
        for (int i=1;i<=k;i++)
        {
            scanf("%d",&x[i]);
            sumx[i]=sumx[i-1]+x[i],sumx2[i]=sumx2[i-1]+1ll*x[i]*x[i];
        }
        for (int i=1;i<=k;i++)
        {scanf("%d",&y[i]);y[k+i]=y[i]+n;}
        for (int i=1;i<=2*k;i++)
        sumy[i]=sumy[i-1]+y[i],sumy2[i]=sumy2[i-1]+1ll*y[i]*y[i];

        for (int i=1;i<=k;i++) fx[i-1].r=x[i];
        for (int i=0,j=2*k;j;i++,j--) fy[i].r=y[j];
        len=1,L=0;
        for (;len<2*k;len<<=1,L++);
        L++;len<<=1;
        for (int i=0;i<len;i++) rev[i]=(rev[i>>1]>>1)|(i&1)<<(L-1);
        fft(fx,len,1);fft(fy,len,1);
        for (int i=0;i<len;i++) fx[i]=fx[i]*fy[i];
        fft(fx,len,-1);
        ll re,c,b,ans=1e13;
        for (int i=2*k-1,j=0;i>=k;i--,j++)
        {
            re=fx[i].r+0.2;
            re=-2*re+sumx2[k]+sumy2[j+k]-sumy2[j];
            b=2*(sumx[k]-sumy[j+k]+sumy[j]);
            c=-b/(2*k);
            ans=min(ans,k*c*c+c*b+re);
            c++;
            ans=min(ans,k*c*c+c*b+re);
        }
        cout<<ans<<endl;
    }
}

原文地址:https://www.cnblogs.com/coco-night/p/9715310.html

时间: 2024-08-04 14:02:11

[2016北京集训试题15]项链-[FFT]的相关文章

[2016北京集训试题6]网络战争-[最小割树(网络流)+kd-tree+倍增]

Description A 联邦国有 N 个州,每个州内部都有一个网络系统,有若干条网络线路,连接各个 州内部的城市. 由于 A 国的州与州之间的关系不是太好,每个州都只有首府建立了到别的州的网络.具体来说,每个州的首府都只主动地建立了一条网络线路,连接到距离最近的州的 首府.(欧氏距离.如果有多个,选择标号最小的去连接) B 国探知了 A 国的网络线路分布情况,以及攻陷每条网络线路所需花费的代价,B 国首脑想知道断开 A 国某两个城市之间的网络连接,所需的最少代价.请你计算出来告 诉他. 注:

[2016北京集训试题14]股神小D-[LCT]

Description Solution 将(u,v,l,r)换为(1,u,v,l)和(2,u,v,r).进行排序(第4个数为第一关键字,第1个数为第二关键字).用LCT维护联通块的合并和断开.(维护联通块的大小,要维护虚边) 答案统计:每当四元组的第一个数为1(这时候合并点u,v所在连通块,反之拆开),在合并前ans+=size[u]*size[v]即可. Code #include<iostream> #include<cstdio> #include<cstring&g

【2016北京集训测试赛(八)】 crash的数列

Description 题解 题目说这是一个具有神奇特性的数列!这句话是非常有用的因为我们发现,如果套着这个数列的定义再从原数列引出一个新数列,它居然还是一样的...... 于是我们就想到了能不能用多点数列套着来加速转移呢? 但是发现好像太多数列套起来是可以烦死人的...... 我们就采用嵌套两次吧,记原数列为A,第一层嵌套为B,第二层嵌套为C. 我们其实可以发现一些规律,对于Ci,它对应了B中i的个数:对于Bi,它对应了A中i的个数. 稍加处理即可,我们一边计算一边模拟数列的运算,同时可以计算

[2016北京集训测试赛15]statement-[线段树+拆环]

Description Solution 由于题目要求,将a[i]->b[i](边权为i)后所得的图应该是由森林和环套树组合而成. 假如是树形结构,所有的t[i]就直接在线段树t[i]点的dfs序(即in[t[i]],out[t[i]]区间)处记录t[i]点的深度. 这样,针对所有的f[i],在线段树上查找所有包含in[f[i]]点的区间所记录的最大深度d.(这个深度就是在离f[i]最近并且已经验证了是真命题的祖先的深度) 然后用倍增算出f[i]向上到深度d,所经过的编号最大值c.ans=min

【2016北京集训测试赛(八)】直径

注意:时限更改为4s 题解 考虑最原始的直径求法:找到离根节点(或离其他任意一点)最远的节点far1,再从far1出发找到离far1最远的节点far2,far1至far2的距离即为直径. 题目中提到了将原树的子树复制成新子树这一操作,显然如果我们将子树真正复制出来是会爆炸的. 实际上我们可以将每棵新子树中,真正有用的节点提取出来,以简化每个子树的结构,再按照题目的要求连接各个新子树. 我们用虚树来重构每一棵子树.每棵子树的虚树的关键点应至少包含: 子树的根节点. 这棵子树内部的直径的两端节点.

【2016北京集训测试赛(七)】自动机 (思考题)

Time Limit: 1000 ms Memory Limit: 256 MB Description Solution 这是一道看起来令人毫无头绪的题,然而确实十分简单巧妙TAT. 题目要求所有点执行相同指令后都回到初始状态. 我们先来考虑只有两种状态的情况:初始状态$T_0$与另一个状态$T_x$. 这样,我们可以通过一个二元记忆化深搜,来得到一种方案A,使得$T_0$回到$T_0$,且$T_x$回到$T_0$.如果这个方案都不存在,那么此时无解. 现在我们知道,执行方案A后,$T_x$与

【2016北京集训测试赛】river

HINT 注意是全程不能经过两个相同的景点,并且一天的开始和结束不能用同样的交通方式. [吐槽] 嗯..看到这题的想法的话..先想到了每个点的度为2,然后就有点不知所措了 隐隐约约想到了网络流,但并没有继续往下想了... 听完学长的讲评之后(%xj)个人觉得建图还是很有意思的ovo [题解] 因为每个点到对面都有k种方式,那就想到每个点原来的点$x_0$拆成k个点$x_1$, $x_2$, $x_3$... $x_k$ 然后很自然地$x_0$和拆成的点之间要连边 容量的话,因为hint里面的限制

【2016北京集训测试赛】azelso(unfinished)

[吐槽] 首先当然是要orzyww啦 以及orzyxq奇妙顺推很强qwq 嗯..怎么说呢虽然说之前零零散散做了一些概d的题目但是总感觉好像并没有弄得比较明白啊..(我的妈果然蒟蒻) 这题的话可以说是难得的一道搞得比较清楚的概d题目吧记录一下还是挺有意思的ovo 当然咯..显然考场上并没有推出来..嗯qwq [题解] 看到说要求期望的距离,然后总的长度又被分成了一段一段的(各个事件) 所以就有一个比较直接的想法:将每一段期望走的次数算出来然后再乘上每一段的距离,加起来就是答案啦 那么现在问题来了怎

2016北京集训测试赛(十七)- 小结

先说一下总体的情况. 场上期望得分 50 + 40 + 30 = 120 , 最后得分 50 + 0 + 30 = 80 , 实际上自己能力所及能做到的 50 + 65 + 30 = 145 分. 第二题爆零是因为我开始写了一个做法, 后来发现这个做法是错的, 然后开始随机化, 调着调着突然发现只有一分钟了, 然后自己把之前调的改回来, 然后发现怎么全都输出 0 ??? Excuse me ?? 原本不用随机化的做法可以拿 40 分, 如果结合上暴力就有 65 了. 这几天打起比赛来还是暴露了许