zoukankan      html  css  js  c++  java
  • [HNOI2017]礼物

    Description

    我的室友最近喜欢上了一个可爱的小女生。马上就要到她的生日了,他决定买一对情侣手环,一个留给自己,一个送给她。每个手环上各有 n 个装饰物,并且每个装饰物都有一定的亮度。
    但是在她生日的前一天,我的室友突然发现他好像拿错了一个手环,而且已经没时间去更换它了!他只能使用一种特殊的方法,将其中一个手环中所有装饰物的亮度增加一个相同的自然数 c(即非负整数)。并且由于这个手环是一个圆,可以以任意的角度旋转它,但是由于上面装饰物的方向是固定的,所以手环不能翻转。需要在经过亮度改造和旋转之后,使得两个手环的差异值最小。
    在将两个手环旋转且装饰物对齐了之后,从对齐的某个位置开始逆时针方向对装饰物编号1,2,…,n,其中 n 为每个手环的装饰物个数, 第 1 个手环的 i 号位置装饰物亮度为 \(x_i\),第 2 个手环的 i 号位置装饰物亮度为 \(y_i\),两个手环之间的差异值为\(\sum_{i=1}^{n}(x_i-y_i)^2\)

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

    HINT

    \(1\leq n\leq50000, 1\leq m\leq100, 1\leq a_i\leq m\).

    Solution

    \(\begin{split}&\sum(x_i+c-y_i)^2\\=&\sum(x_i^2+y_i^2)+[nc^2+2c\sum(x_i-y_i)]-2\sum x_iy_i\end{split}\)

    关于c的二次函数可以直接枚举求最值.

    再求个循环卷积就解决了.

    #define N 50005
    #define K 131073
    typedef long double ld;
    const ld pi=acos(-1.0);
    struct cp{
    	ld x,y;
    	cp() {}
    	cp(ld x,ld y):x(x),y(y) {}
    	friend cp operator + (cp a,cp b){
    		return cp(a.x+b.x,a.y+b.y);
    	}
    	friend cp operator - (cp a,cp b){
    		return cp(a.x-b.x,a.y-b.y);
    	}
    	friend cp operator * (cp a,cp b){
    		return cp(a.x*b.x-a.y*b.y,a.y*b.x+a.x*b.y);
    	}
    }a1[K],b1[K],a2[K],b2[K];
    namespace FFT{
    	int re[K],n;cp w[2][K];
    	inline void init(int k){
    		k<<=1;n=1;while(n<k) n<<=1;
    		for(int i=0;i<n;++i){
    			w[0][i]=cp(cos(pi*2/n*i),sin(pi*2/n*i));
    			w[1][i]=cp(w[0][i].x,-w[0][i].y);
    		}
    		k=0;while((1<<k)<n) ++k;
    		for(int i=0,t;i<n;++i){
    			t=0;
    			for(int j=0;j<k;++j)
    				if(i&(1<<j)) t|=(1<<k-j-1);
    			re[i]=t;
    		}
    	}
    	inline void DFT(cp *a,int ty){
    		cp *o=w[ty];
    		for(int i=0;i<n;++i)
    			if(i<re[i]) swap(a[i],a[re[i]]);
    		cp tmp;
    		for(int l=2,m;l<=n;l<<=1){
    			m=l>>1;
    			for(cp *p=a;p!=a+n;p+=l)
    				for(int i=0;i<m;++i){
    					tmp=o[n/l*i]*p[i+m];
    					p[i+m]=p[i]-tmp;p[i]=p[i]+tmp;
    				}
    		}
    		if(ty) for(int i=0;i<n;++i)
    			a[i].x/=(ld)(n),a[i].y/=(ld)(n);
    	}
    }
    int x[N],y[N],n,m,ans,tot;
    inline int read(){
    	int ret=0;char c=getchar();
    	while(!isdigit(c))
    		c=getchar();
    	while(isdigit(c)){
    		ret=(ret<<1)+(ret<<3)+c-'0';
    		c=getchar();
    	}
    	return ret;
    }
    //\sum(x_i+c-y_i)^2=\sum(x_i^2+y_i^2)+[nc^2+2c\sum(x_i-y_i)]-\sum2x_iy_i
    inline void Aireen(){
    	n=read();m=read();
    	for(int i=0;i<n;++i) x[i]=read();
    	for(int i=0;i<n;++i) y[i]=read();
    	for(int i=0;i<n;++i) tot+=x[i]-y[i];
    	for(int i=-m;i<=m;++i) 
    		ans=min(ans,n*i*i+2*i*tot);
    	tot=ans;ans=0;
    	for(int i=0;i<n;++i)
    		tot+=x[i]*x[i]+y[i]*y[i];
    	for(int i=0;i<n;++i)
    		ans+=x[i]*y[i];
    	for(int i=0;i<n;++i)
    		a1[i]=cp((ld)x[i],0.0),b1[i]=cp((ld)y[n-i-1],0.0),
    		a2[i]=cp((ld)x[n-i-1],0.0),b2[i]=cp((ld)y[i],0.0);
    	FFT::init(n);
    	FFT::DFT(a1,0);FFT::DFT(b1,0);
    	for(int i=0;i<FFT::n;++i)
    		a1[i]=a1[i]*b1[i];
    	FFT::DFT(a1,1);
    	FFT::DFT(a2,0);FFT::DFT(b2,0);
    	for(int i=0;i<FFT::n;++i)
    		a2[i]=a2[i]*b2[i];
    	FFT::DFT(a2,1);
    	ans=(int)(a1[n-1].x+0.5);
    	for(int i=0;i<n;++i)
    		ans=max(ans,(int)(a1[i].x+a2[n-i-2].x+0.5));
    	printf("%d\n",tot-(ans<<1));
    }
    

    2017-04-22 08:44:13

  • 相关阅读:
    freopen stdout 真的更快?
    【评分】第二次作业——个人项目实战
    【评分】第二次作业-数独-第一次测试成绩
    姑娘你大胆地往前走——答大二学生XCL之八问
    第二次作业-数独-初步测试日志
    第二次作业——个人项目实战
    关于C#的随机数
    必须展示窗口才能截图怎么办,伪后台截图思路
    Winform 奇怪的 英文字体错乱显示问题
    wpf 解决 WPF SelectionChanged事件向上传递造成重复执行不想执行的函数的问题
  • 原文地址:https://www.cnblogs.com/AireenYe/p/15602587.html
Copyright © 2011-2022 走看看