zoukankan      html  css  js  c++  java
  • 【BZOJ4827】[Hnoi2017]礼物 FFT

    【BZOJ4827】[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个数,分别代表第一条手环和第二条手环上从某个位置开始逆时 针方向上各装饰物的亮度。
    1≤n≤50000, 1≤m≤100, 1≤ai≤m

    Output

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

    Sample Input

    5 6
    1 2 3 4 5
    6 3 3 4 5

    Sample Output

    1
    【样例解释】
    需要将第一个手环的亮度增加1,第一个手环的亮度变为: 2 3 4 5 6 旋转一下第二个手环。对于该样例,是将第
    二个手环的亮度6 3 3 4 5向左循环移动一个位置,使得第二手环的最终的亮度为
    :3 3 4 5 6。 此时两个手环的亮度差异值为1。

    题解:题中式子:

    遇见式子不要害怕嘛,我们将它拆开来看

    发现前面那个东西跟c无关,中间那个就是sumx-sumy,所以这变成了一个二次函数求对称轴的问题,直接O(1)计算出c就好了,因此,c是一个定值!

    然后我们将xi都加上c,于是就有回到了题中给的那个式子,发现如果将x旋转,相当于x[i]变成x[i+j](将x倍长一遍),于是我们再将原式拆开

    又一次发现前面那两个东西是一个定值,我们只要求出最后面那个东西就好了,发现我们将y数组反转后它就变成了一个卷积,直接用FFT求解

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <cmath>
    #include <algorithm>
    #define pi acos(-1.0)
    using namespace std;
    struct cp
    {
    	double x,y;
    	cp (double a,double b){x=a,y=b;}
    	cp (){}
    	cp operator + (cp a){return cp(x+a.x,y+a.y);}
    	cp operator - (cp a){return cp(x-a.x,y-a.y);}
    	cp operator * (cp a){return cp(x*a.x-y*a.y,x*a.y+y*a.x);}
    }n1[1<<20],n2[1<<20];
    int n,m,C,sumx,sumy,X[1<<20],Y[1<<20],ans[1<<20],minn;
    int rd()
    {
    	int ret=0,f=1;	char gc=getchar();
    	while(gc<'0'||gc>'9')	{if(gc=='-')f=-f;	gc=getchar();}
    	while(gc>='0'&&gc<='9')	ret=ret*10+gc-'0',gc=getchar();
    	return ret*f;
    }
    void FFT(cp *a,int len,int f)
    {
    	int i,j,k,h;
    	cp t;
    	for(i=k=0;i<len;i++)
    	{
    		if(i>k)	swap(a[i],a[k]);
    		for(j=(len>>1);(k^=j)<j;j>>=1);
    	}
    	for(h=2;h<=len;h<<=1)
    	{
    		cp wn(cos(f*2*pi/h),sin(f*2*pi/h));
    		for(j=0;j<len;j+=h)
    		{
    			cp w(1,0);
    			for(k=j;k<j+h/2;k++)	t=w*a[k+h/2],a[k+h/2]=a[k]-t,a[k]=a[k]+t,w=w*wn;
    		}
    	}
    }
    void work(cp *a,cp *b,int len)
    {
    	FFT(a,len,1),FFT(b,len,1);
    	for(int i=0;i<len;i++)	a[i]=a[i]*b[i];
    	FFT(a,len,-1);
    	for(int i=0;i<len;i++)	ans[i]=(int)(a[i].x/len+0.1);
    }
    int main()
    {
    	n=rd(),m=rd(),minn=1<<30;
    	int i,j,len=1,tmp=0;
    	while(len<3*n)	len<<=1;
    	for(i=0;i<n;i++)	X[i]=rd(),sumx+=X[i];
    	for(i=0;i<n;i++)	Y[i]=rd(),sumy+=Y[i];
    	C=(sumy-sumx)/n;
    	if(abs(sumy-sumx-n*C)>abs(sumy-sumx-n*C-n))	C++;
    	if(abs(sumy-sumx-n*C)>abs(sumy-sumx-n*C+n))	C--;
    	if(C>0)	for(i=0;i<n;i++)	X[i]+=C;
    	else	for(i=0;i<n;i++)	Y[i]+=C;
    	for(i=0;i<n;i++)	tmp+=X[i]*X[i],n1[i]=n1[i+n]=cp(1.0*X[i],0.0);
    	for(i=0;i<n;i++)	tmp+=Y[i]*Y[i],n2[n-i-1]=cp(1.0*Y[i],0.0);
    	work(n1,n2,len);
    	for(i=0;i<n;i++)	minn=min(minn,tmp-2*ans[n+i-1]);
    	printf("%d",minn);
    	return 0;
    }
  • 相关阅读:
    A1052. Linked List Sorting (25)
    A1032. Sharing (25)
    A1022. Digital Library (30)
    A1071. Speech Patterns (25)
    A1054. The Dominant Color (20)
    A1060. Are They Equal (25)
    A1063. Set Similarity (25)
    电子码表
    矩阵键盘
    对象追踪、临时对象追踪、绝对坐标与相对坐标
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/6878776.html
Copyright © 2011-2022 走看看