zoukankan      html  css  js  c++  java
  • 项链

    升级版AHOI/HNOI 2017礼物

    题目大意

    有两个排数$A,B$,每一排都有小于$m$的$n$个数,你可以任意的对某一排整体$+1$,然后找到一个排列$P$,记$d(x,y)=min(|x-y|^2,(m-|x-y|)^2)$使得$sumlimits_{i=1}^{n}d(A_i,B_{P_i})$最小。

     

    题解

    把两排数放在两个相同数轴上,其中实心的格子表示这个位置有数。整体加一就可以变成将这个轴向右移,再将最右侧的格子补到左边。考虑一件事情,由于对于确定的$A_i,B_{P_i}$,在轴之间连一条线,若它们的值的计算方式不是以$|x-y|^2$计算,则需要跨越左右边界。

    如果这样画图,那么在最优解中,线一定不会交叉。若存在两条交叉的线,交换他们的匹配,结果一定会更优。这意味着当我们确定$A_i$匹配$B_i+k$时,对于任意的$A_j$,一定匹配$B_{j+k}$(当$j+k>n$时匹配$B_{j+k-n}$)。也就是说,对于$B_i$若连向它的线是跨过边界的,那么对于所有这样$B_i$一定恰好是$B$的前缀。到这里,我们应该想到将下方的那排数倍长($B_{i+n}=B_i+m$)。

    这样做还有一个好处,我们可以简化整体$+1$的操作。由于对于两个数组都进行一次$+1$的操作是没有意义的,不妨只对$A$进行操作。由于倍长了$B$,我们甚至可以不用取模。因为最多有意义的$+1$次数不超过$m$,而且每一种匹配的方式都可以在倍长$B$之后体现为$A_i ightarrow B_{i+k}$,即上图中出现了跨越边界可以视为在倍长的$B$数组中匹配。

    然后问题就变成了求$minsumlimits_{i=1}^{n}(A_i+d-B_{i+k})^2$。其中$d$表示对$A$进行$+1$的次数,$k$表示匹配的编号错位的量。

    你很容易发现$0leq k<n$,然后我们就考虑枚举$k$,就有

    $$Ans=sumlimits_{i=1}^{n}(A_i+d-B_{i+k})^2$$

    $$=sumlimits_{i=1}^{n}A_i^2+d^2-B_{i+k}^2+2(A_i-B_{i+k})d-2A_icdot B_{i+k}$$

    $$Ans=t1+t2+t3$$

    $$t1=sumlimits_{i=1}^{n}A_i^2-B_{i+k}^2$$

    $$t2=nd^2+(2sumlimits_{i=1}^{n}A_i-B_{i+k})d$$

    $$t3=sumlimits_{i=1}^{n}-2A_icdot B_{i+k}$$ 

    不难发现$t1$是我们可以预处理出来的,$t3$是一个减法意义下的卷积,可以通过将一个数组反转再用$FFT$做加法卷积预处理,而$t2$只有一个未知数$d$,而这恰好又是关于$d$的二次函数$n>0$决定了函数有最小值,所以我们可以通过计算二次函数对称轴的方式来求得$d$(注意$d$必须要临近取整,因为$+1$操作只能进行整数次,但是可以为负数,因为这表示相对的对$B$进行操作),求得$d$后就直接计算就可以了。对于每一个枚举的$k$计算答案,最后取$min$即可。

    复杂度为$O(T(n+nlog n))$。

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    #define LL long long
    #define M 262170
    using namespace std;
    int read(){
        int nm=0,fh=1; char cw=getchar();
        for(;!isdigit(cw);cw=getchar()) if(cw=='-') fh=-fh;
        for(;isdigit(cw);cw=getchar()) nm=nm*10+(cw-'0');
        return nm*fh;
    }
    const double PI=acos(-1);
    struct comp{
        double r,k; comp(){}
        comp(double _r,double _k){r=_r,k=_k;}
        comp operator *(const comp&ot)const{return comp(r*ot.r-k*ot.k,r*ot.k+k*ot.r);}
        comp operator +(const comp&ot)const{return comp(r+ot.r,k+ot.k);}
        comp operator -(const comp&ot)const{return comp(r-ot.r,k-ot.k);}
    }A[M],B[M],C[M];
    LL n,m,sumx[M],sumy[M],dt,X[M],Y[M],sx[M],sy[M],od[M],len,ans,nw;
    void FFT(comp *x,double kd){
        for(int i=1;i<len;i++) if(i<od[i]) swap(x[i],x[od[i]]);
        for(int tt=1;tt<len;tt<<=1){
            comp unit(cos(PI*kd/(tt*1.0)),sin(PI*kd/(tt*1.0)));
            for(int st=0;st<len;st+=(tt<<1)){
                comp now(1.0,0.0);
                for(int pos=st;pos<st+tt;pos++,now=now*unit){
                    comp t1=x[pos],t2=x[pos+tt]*now;
                    x[pos]=t1+t2,x[pos+tt]=t1-t2;
                }
            }
        }
        if(kd<0.0){for(int i=0;i<len;i++) x[i].r/=(len*1.0);}
    }
    int main(){
        for(int Cs=read();Cs;Cs--){
            m=read(),n=read(),memset(&ans,0x3f,sizeof(LL));
            for(len=1,nw=-1;len<n*3;len<<=1,nw++);
            for(int i=0;i<len;i++) A[i]=B[i]=comp(0.0,0.0),od[i]=((od[i>>1]>>1)|((i&1)<<nw));
            for(int i=1;i<=n;i++) X[i]=read(),sumx[i]=sumx[i-1]+X[i];
            for(int i=1;i<=n;i++) Y[i]=read(),Y[i+n]=Y[i]+m,sumy[i]=sumy[i-1]+Y[i];
            for(int i=1;i<=n;i++){
                sumy[i+n]=sumy[i+n-1]+Y[i+n];
                sx[i]=sx[i-1]+X[i]*X[i],sy[i]=sy[i-1]+Y[i]*Y[i];
            }
            for(int i=n+1;i<=(n<<1);i++) sy[i]=sy[i-1]+Y[i]*Y[i];
            for(int i=0;i<n;i++) A[i]=comp(X[i+1]*1.0,0.0);
            for(int i=0;i<(n<<1);i++) B[i]=comp(Y[(n<<1)-i]*1.0,0.0);
            FFT(A,1.0),FFT(B,1.0);
            for(int i=0;i<len;i++) C[i]=A[i]*B[i]; FFT(C,-1.0);
            for(int k=0;k<n;k++){
                LL now=((LL)(C[(n<<1)-1-k].r+0.5)); now<<=1;
                LL dt=(LL)round((((sumy[n+k]-sumy[k])-sumx[n])*1.0)/(n*1.0));
                LL tk=n*dt*dt+2*dt*(sumx[n]-(sumy[n+k]-sumy[k]));
                ans=min(ans,sx[n]+sy[n+k]-sy[k]+tk-now);
            } printf("%lld
    ",ans);
        }
        return 0;
    }
    

      

  • 相关阅读:
    苹果p12文件--一个苹果证书怎么多次使用(蛋疼,这些问题只有和其他企业合作才会遇到,别人的账号不可能给你,蛋疼....)
    xcode 树形管理 cocos2d-x的资源
    cocos2d-x 扩充引擎基类功能 引起的头文件重复包含问题的分析
    pytest--运行指定的测试和参数化
    adb--常用命令
    appium--desktop
    adb--环境安装
    pytest--命令行常用参数
    django -- auth模块
    pytest--常用插件
  • 原文地址:https://www.cnblogs.com/OYJason/p/9712313.html
Copyright © 2011-2022 走看看