zoukankan      html  css  js  c++  java
  • [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;
        }
    }
  • 相关阅读:
    loj#6433. 「PKUSC2018」最大前缀和(状压dp)
    PKUWC2019游记
    10. Regular Expression Matching
    9. Palindrome Number
    8. String to Integer (atoi)
    7. Reverse Integer
    6. ZigZag Conversion
    5. Longest Palindromic Substring
    4. Median of Two Sorted Arrays
    3. Longest Substring Without Repeating Characters
  • 原文地址:https://www.cnblogs.com/coco-night/p/9715310.html
Copyright © 2011-2022 走看看