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;
    }
  • 相关阅读:
    NYOJ--1058--dfs--部分和问题
    js中数组的操作方法
    eval()函数
    ES6 对象新增方法 object.is() object.assign()
    vue 中的nextTick
    vue vue-cli创建项目步骤方法
    node express创建项目步骤
    get post put delete
    vue中的状态管理 vuex store
    vue的实例属性$options
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/6878776.html
Copyright © 2011-2022 走看看