礼物:多项式
Description:
我的室友最近喜欢上了一个可爱的小女生。马上就要到她的生日了,他决定买一对情侣手环,一个留给自己,一个送给她。每个手环上各有n个装饰物,并且每个装饰物都有一定的亮度。
但是在她生日的前一天,我的室友突然发现他好像拿错了一个手环,而且已经没时间去更换它了!
他只能使用一种特殊的方法,将其中一个手环中所有装饰物的亮度增加一个相同的整数x(可能是负数)。
并且由于这个手环是一个圆,可以以任意的角度旋转它,但是由于上面装饰物的方向是固定的,所以手环不能翻转。需要在经过亮度改造和旋转之后,使得两个手环的差异值最小。
在将两个手环旋转且装饰物对齐了之后,从对齐的某个位置开始逆时针方向对装饰物编号1,2,...,n,其中n为每个手环的装饰物个数。第一个手环的i号位置装饰物亮度为$a_i$ ,第二个手环的j号位置装饰物亮度$b_j$。两个手环之间的差异值为:$\sum\limits_{i=1}^{n} (a_i-b_i)^2$
麻烦你帮他计算一下,进行调整(亮度改造和旋转),使得两个手环之间的差异值最小,这个最小值是多少呢?
n<=50000 m<=100
skyh说这道题是水题。
然后NC在那里笑,我就以为是skyh在骗我。于是我想暴打他。
然而我在化学学考上想了十几分钟就会了,所以我就不打算暴打skyh了。
断环成链是常识。
——By Paris
所以就把一个手环断开。
先假如它已经对齐了。想想最后的答案吧。
$\sum\limits_{i=1}^{n} (a_i - b_i - x)^2$
$=\sum\limits_{i=1}^{n} a_i^2 + b_i^2 + x^2 -2a_i x + 2 b_i x - 2 a_i b_i$
于是发现关于x的部分可以解一元二次方程解决。然而我不会,所以枚举x值取最优也是可以的。
(我本来会的可是不知道为什么WA90自闭)
所以上面这个式子唯一一个需要求的就是$\sum\limits_{i=1}^{n} a_i \times b_i$
而这里ab可以错位,错位之后还要求和。怎么办?
假如对齐位置是p,那么断环成链后就是$\sum\limits_{i=1}^{n} a_{p+i} \times b_i$
这个形式就是《快速傅丽叶变化之二》。把b翻转就完了。
1 #include<cstdio> 2 #define mod 998244353 3 #define int long long 4 int max(int a,int b){return a>b?a:b;} 5 int a[263333],b[263333],n,A,B,ans,len=1,rev[263333],mx=-1e16,m,mx2=-1e16; 6 int pow(int b,int t,int a=1){for(;t;t>>=1,b=b*b%mod)if(t&1)a=a*b%mod;return a;} 7 void NTT(int *a,int opt){ 8 for(int i=0;i<len;++i)if(rev[i]>i)a[i]^=a[rev[i]]^=a[i]^=a[rev[i]]; 9 for(int mid=1;mid<len;mid<<=1) 10 for(int i=0,t=pow(3,(mod-1)/mid/2*opt+mod-1);i<len;i+=mid<<1) 11 for(int j=0,w=1,x,y;j<mid;++j,w=w*t%mod) 12 x=a[i+j],y=a[i+j+mid]*w%mod,a[i+j]=(x+y)%mod,a[i+j+mid]=(x-y+mod)%mod; 13 if(opt==-1)for(int i=0,iv=pow(len,mod-2);i<len;++i)a[i]=a[i]*iv%mod; 14 } 15 signed main(){ 16 scanf("%lld%lld",&n,&m); 17 for(int i=0;i<n;++i)scanf("%lld",&a[i]),ans+=a[i]*a[i],a[i+n]=a[i],A+=a[i]; 18 for(int i=0;i<n;++i)scanf("%lld",&b[i]),ans+=b[i]*b[i],B+=b[i]; 19 while(len<=n*3)len<<=1; 20 for(int x=-m;x<=m;++x)mx2=max(mx2,-n*x*x+2*(A-B)*x); 21 ans-=mx2; 22 for(int i=0;i<n-1-i;++i)b[i]^=b[n-1-i]^=b[i]^=b[n-1-i]; 23 for(int i=1;i<len;++i)rev[i]=rev[i>>1]>>1|(i&1?len>>1:0); 24 NTT(a,1);NTT(b,1);for(int i=0;i<len;++i)a[i]=a[i]*b[i]%mod;NTT(a,-1); 25 for(int i=0;i<n;++i)mx=max(mx,a[i+n]); 26 printf("%lld\n",ans-2*mx); 27 }