zoukankan      html  css  js  c++  java
  • 【HNOI2017】礼物

    题面

    Description

    我的室友最近喜欢上了一个可爱的小女生。马上就要到她的生日了,他决定买一对情侣手环,一个留给自己,一个送给她。每个手环上各有 n 个装饰物,并且每个装饰物都有一定的亮度。

    但是在她生日的前一天,我的室友突然发现他好像拿错了一个手环,而且已经没时间去更换它了!他只能使用一种特殊的方法,将其中一个手环中所有装饰物的亮度增加一个相同的自然数 c(即非负整数)。并且由于这个手环是一个圆,可以以任意的角度旋转它,但是由于上面装饰物的方向是固定的,所以手环不能翻转。需要在经过亮度改造和旋转之后,使得两个手环的差异值最小。

    在将两个手环旋转且装饰物对齐了之后,从对齐的某个位置开始逆时针方向对装饰物编号1,2,…,n,其中 n 为每个手环的装饰物个数, 第 1 个手环的 i 号位置装饰物亮度为 xi,第 2 个手环的 i 号位置装饰物亮度为 yi,两个手环之间的差异值为(参见输入输出样例和样例解释):

    [sum_{i=1}^n(x_i-y_i)^2 ]

    麻烦你帮他计算一下,进行调整(亮度改造和旋转),使得两个手环之间的差异值最小,这个最小值是多少呢?

    Input

    输入数据的第一行有两个数n, m,代表每条手环的装饰物的数量为n,每个装饰物的初始亮度小于等于m。

    接下来两行,每行各有n个数,分别代表第一条手环和第二条手环上从某个位置开始逆时针方向上各装饰物的亮度。

    Output

    输出一个数,表示两个手环能产生的最小差异值。注意在将手环改造之后,装饰物的亮度可以大于 m。

    Sample Input

    5 6

    1 2 3 4 5

    6 3 3 4 5

    Sample Output

    1

    Hint

    【样例解释】

    需要将第一个手环的亮度增加1,第一个手环的亮度变为: 2 3 4 5 6

    旋转一下第二个手环。对于该样例,是将第二个手环的亮度6 3 3 4 5向左循环移动一个位置,使得第二手环的最终的亮度为: 3 3 4 5 6。

    此时两个手环的亮度差异值为1。

    【数据范围】

    30%的数据满足n≤500, m≤10;

    70%的数据满足n≤5000;

    100%的数据满足1≤n≤50000, 1≤m≤100, 1≤ai≤m。

    题目分析

    由于可以选择一个装饰物加上非负数,等价于固定一个装饰物加上任意实数(x)

    [egin{split} sum_{i=1}^n(a_i-b_i+x)^2&=sum_{i=1}^n(a_i^2+b_i^2+x^2+2cdot x(a_i-b_i)-2a_ib_i)\ &=sum_{i=1}^n(a_i^2+b_i^2)+(ncdot x^2+2cdot x(sum_{i=1}^n(a_i-b_i)))-2sum_{i=1}^na_ib_i end{split} ]

    其中,第一部分为定值,第二部分为二次函数(x=-frac {sumlimits_{i=1}^n(a_i-b_i)} n)时为最值。

    第三部分,如果我们把(a)数组反转,相当于(sum_{i=1}^na_{n-i}b_i),此时,这就相当于一个卷积的形式。

    对于旋转手环,我们只需把(a)数组复制两份求卷积,在最后(ans_{n+1}sim ans_{2n})中取最大值即可。

    代码实现

    #include<iostream>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<cstdio>
    #include<iomanip>
    #include<cstdlib>
    #include<complex> 
    #define MAXN 0x7fffffff
    typedef long long LL;
    const int N=270005;
    using namespace std;
    inline int Getint(){register int x=0,f=1;register char ch=getchar();while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}return x*f;}
    typedef complex<double> Z;
    const double Pi=M_PI; 
    void FFT(Z *a,int x,int K){
    	static int rev[N],lst;
    	int n=1<<x;
    	if(n!=lst){
    		for(int i=0;i<n;i++)rev[i]=(rev[i>>1]>>1)|((i&1)<<x-1);
    		lst=n;
    	} 
    	for(int i=0;i<n;i++)if(i<rev[i])swap(a[i],a[rev[i]]);
    	for(int i=1;i<n;i<<=1){
    		int tmp=i<<1;
    		Z wn(cos(Pi/i),sin(K*Pi/i));
    		for(int j=0;j<n;j+=tmp){
    			Z w(1,0);
    			for(int k=0;k<i;k++,w=w*wn){
    				Z x=a[j+k],y=w*a[i+j+k];
    				a[j+k]=x+y,a[i+j+k]=x-y;
    			}
    		}
    	}
    	if(K==-1)for(int i=0;i<n;i++)a[i]/=n;
    } 
    Z a[N],b[N];
    LL ans,sum;
    int main(){
    	int n=Getint(),m=Getint();
    	for(int i=n;i>=1;i--){
    		int x=Getint();
    		a[i+n].real()=a[i].real()=x,ans+=x*x,sum+=x; 
    	}
    	for(int i=1;i<=n;i++){
    		int x=Getint();
    		b[i].real()=x,ans+=x*x,sum-=x;
    	}
    	double t=-1.0*sum/n;
    	ans=ans+min(ceil(t)*ceil(t)*n+2*ceil(t)*sum,floor(t)*floor(t)*n+2*floor(t)*sum);
    	int x=ceil(log2(n*3+1));
    	FFT(a,x,1),FFT(b,x,1);
    	for(int i=0;i<(1<<x);i++)a[i]=a[i]*b[i];
    	FFT(a,x,-1);
    	int ret=0;
    	for(int i=n+1;i<=(n<<1);i++)ret=max(ret,(int)(a[i].real()+0.5));
    	cout<<ans-2*ret;
    	return 0;
    }
    
  • 相关阅读:
    Oracle:PL/SQL--流程控制——作业练习:向表中循环插入ID编号
    Oracle:PL/SQL--流程控制(三)——循环结构:loop、while-loop、for-loop
    Oracle:PL/SQL--流程控制(三)——循环结构:loop、while-loop、for-loop
    Oracle:PL/SQL--打开控制台or关闭控制台
    Win10远程桌面及防火墙配置
    H3C-Telnet
    网络工程师(软考)心得
    《网络工程师 考前冲刺100题》思维导图
    《2019上半年网络工程师考试大纲》
    网络设计:搭建校园网(组网工程课设)【译】
  • 原文地址:https://www.cnblogs.com/Emiya-wjk/p/10028602.html
Copyright © 2011-2022 走看看