zoukankan      html  css  js  c++  java
  • 洛谷P3723 [AH2017/HNOI2017]礼物

    吴迪说他化学会考上十分钟就想出来了,太神了%%%不过我也十分钟

    但是调了一个多小时啊大草

    懒得人话翻译了,自己康吧:

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

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

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

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

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

    对于 (100\%) 的数据,(1 le n le 50000, 1 le a_i le m le 100。)

    考虑加上一个(c)之后式子变为

    [sumlimits_{i=1}^{n}(x_i-y_i+c)^2 ]

    拆一下

    [=sumlimits_{i=1}^{n}x_i^2+y_i^2-2x_iy_i+c^2+c(x_i-y_i) ]

    发现求个(sumlimits_{i=1}^{n}x_iy_i)就完了

    (x^{'})(x)翻转后的序列,那么我们只要求(sumlimits_{x=1}^{n}x_{n-i+1}^{'}y_i)

    发现是个卷积,但是对齐的位置可能不一样怎么办呢?

    可以倍长一下(x_i)再翻转,然后在(ntt)之后的系数数组的(x_{n+1}sim x_{n+n})中选一个

    就切了

    多项式题目的边界真tm恶心

    吴迪的代码为什么那么短啊

    #include<bits/stdc++.h>
    using namespace std;
    namespace red{
    #define int long long
    #define lowbit(x) ((x)&(-x))
    	inline int read()
    	{
    		int x=0;char ch,f=1;
    		for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar());
    		if(ch=='-') f=0,ch=getchar();
    		while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    		return f?x:-x;
    	}
    	const int N=5e5+10,p=998244353,g=3,gi=332748118;
    	int n,m,limit,len;
    	int suma,sumb,sum;
    	int ret=1e9+7;
    	int a[N],pos[N];
    	int b[N];
    	inline int fast(int x,int k)
    	{
    		int ret=1;
    		while(k)
    		{
    			if(k&1) ret=ret*x%p;
    			x=x*x%p;
    			k>>=1;
    		}
    		return ret;
    	}
    	inline void ntt(int *a,int inv)
    	{
    		for(int i=0;i<limit;++i)
    			if(i<pos[i]) swap(a[i],a[pos[i]]);
    		for(int mid=1;mid<limit;mid<<=1)
    		{
    			int Wn=fast(inv?g:gi,(p-1)/(mid<<1));
    			for(int r=mid<<1,j=0;j<limit;j+=r)
    			{
    				int w=1;
    				for(int k=0;k<mid;++k,w=w*Wn%p)
    				{
    					int x=a[j+k],y=w*a[j+k+mid]%p;
    					a[j+k]=x+y;
    					if(a[j+k]>=p) a[j+k]-=p;
    					a[j+k+mid]=x-y;
    					if(a[j+k+mid]<0) a[j+k+mid]+=p;
    				}
    			}
    		}
    	}
    	inline void main()
    	{
    		n=read(),m=read();
    		for(int i=1;i<=n;++i) a[i]=a[i+n]=read(),suma+=a[i],sum+=a[i]*a[i];
    		for(int i=1;i<=n;++i) b[i]=read(),sumb+=b[i],sum+=b[i]*b[i];
    		reverse(a+1,a+2*n+1);
    		for(limit=1;limit<=3*n;limit<<=1) ++len;
    		for(int i=0;i<limit;++i) pos[i]=(pos[i>>1]>>1)|((i&1)<<(len-1));
    		ntt(a,1),ntt(b,1);
    		for(int i=0;i<limit;++i) a[i]=a[i]*b[i]%p;
    		ntt(a,0);
    		int inv=fast(limit,p-2);
    		for(int i=0;i<limit;++i) a[i]=a[i]*inv%p;
    		for(int tmp,i=1;i<=n;++i)
    		{
    			for(int d=-m;d<=m;++d)
    			{
    				tmp=sum-2*a[i+n]+d*d*n+2*d*(suma-sumb);
    				ret=min(ret,tmp);
    			}
    		}
    		printf("%lld
    ",ret);
    	}
    }
    signed main()
    {
    	red::main();
    	return 0;
    }
    /*
    5 6
    4 5 1 1 3
    6 3 3 4 5
    
    */
    
  • 相关阅读:
    洛谷P1328 生活大爆炸版石头剪刀布
    洛谷P1131 [ZJOI2007]时态同步
    洛谷P2585 [ZJOI2006]三色二叉树
    机器学习实战四(Logistic Regression)
    机器学习实战三(Naive Bayes)
    机器学习实战二 (Decision Tree)
    机器学习实战一(kNN)
    chapter9 拖放
    Stanford Algorithms(一): 大数相乘(c++版)
    读: 程序员之禅
  • 原文地址:https://www.cnblogs.com/knife-rose/p/12050231.html
Copyright © 2011-2022 走看看