项链 - FFT

题目大意:给你两串项链,长度为n,每条分别有恰好k个黑色珠子。定义两个点距离 d i s ( x , y ) = [ m i n ( x y , n x y ) ] 2 dis(x,y)=\left[min\left(|x-y|,n-|x-y|\right)\right]^2 。你可以旋转其中一串项链任意整数单位距离,然后要找到一个排列p,使得 i = 1 k d i s ( x i , y p i ) \sum_{i=1}^k dis(x_i,y_{p_i}) 最小。其中 x i , y i x_i,y_i 表示两个串第i个黑珠子的位置。
题解:关于那个距离,先令 y i + k = y i + n y_{i+k}=y_i+n 倍长,然后问题转为求:
min s [ 0 , k ) , c [ 0 , n ) F ( s , c ) = i = 0 k 1 ( x i y i + s + c ) 2 \min_{s\in[0,k),c\in[0,n)}F(s,c)=\sum_{i=0}^{k-1}(x_i-y_{i+s}+c)^2
关于后面的那个 F ( s , c ) F(s,c) ,展开后将c视为未知数,使用FFT将其各项系数求出,再取c为对称轴即可。
注意本题要求c必须是整数,所以需要取整后晃荡一下。

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define lint long long
#define N 4010
#define db double
#define gc getchar()
using namespace std;
inline int inn()
{
	int x,ch;while((ch=gc)<'0'||ch>'9');
	x=ch^'0';while((ch=gc)>='0'&&ch<='9')
		x=(x<<1)+(x<<3)+(ch^'0');return x;
}
const db PI=acos(-1);
struct E{
	db x,y;E(db _x=0,db _y=0) { x=_x,y=_y; }
	inline E& operator=(const E &w) { return x=w.x,y=w.y,*this; }
	inline E operator+(const E &w)const{ return E(x+w.x,y+w.y); }
	inline E operator-(const E &w)const{ return E(x-w.x,y-w.y); }
	inline E operator*(const E &w)const{ return E(x*w.x-y*w.y,x*w.y+y*w.x); }
	inline E& operator+=(const E &w) { return x+=w.x,y+=w.y,*this; }
	inline E& operator-=(const E &w) { return x-=w.x,y-=w.y,*this; }
	inline E& operator*=(const E &w) { return (*this)=(*this)*w; }
}a[N<<3],b[N<<3];int x[N],y[N<<1],r[N<<3];lint sy[N<<1],sy2[N<<1],f[N<<2];
lint S(lint *s,int l,int r) { return s[r]-(l?s[l-1]:0); }
inline int FFT(E *a,int n,int s)
{
	for(int i=1;i<n;i++) if(i<r[i]) swap(a[i],a[r[i]]);
	for(int i=1;i<n;i<<=1)
	{
		E wn(cos(PI/i),s*sin(PI/i));
		for(int j=0,t=i<<1;j<n;j+=t)
		{
			E w(1,0);
			for(int k=0;k<i;k++,w*=wn)
			{
				E x=a[j+k],y=w*a[j+k+i];
				a[j+k]=x+y,a[j+k+i]=x-y;
			}
		}
	}
	if(s<0) for(int i=0;i<n;i++) a[i].x/=n,a[i].y/=n;
	return 0;
}
inline int tms(int *A,int *B,lint *C,int m1,int m2)
{
	int n=1,L=0;while(n<m1+m2-1) n<<=1,L++;
	for(int i=1;i<n;i++) r[i]=(r[i>>1]>>1)|((i&1)<<(L-1));
	for(int i=0;i<m1;i++) a[i]=E(A[i],0);
	for(int i=m1;i<n;i++) a[i]=E(0,0);FFT(a,n,1);
	for(int i=0;i<m2;i++) b[i]=E(B[i],0);
	for(int i=m2;i<n;i++) b[i]=E(0,0);FFT(b,n,1);
	for(int i=0;i<n;i++) a[i]*=b[i];FFT(a,n,-1);
	for(int i=0;i<m1+m2-1;i++) C[i]=(lint)(a[i].x+0.5);
	return 0;
}
int main()
{
	for(int T=inn();T;T--)
	{
		int n=inn(),k=inn();lint ans=LLONG_MAX,sx=0,sx2=0;
		for(int i=0;i<k;i++) x[i]=inn(),sx+=x[i],sx2+=x[i]*x[i];
		for(int i=0;i<k;i++) y[i]=inn(),y[i+k]=y[i]+n;
		for(int i=0;i<k/2;i++) swap(x[i],x[k-i-1]);
		tms(x,y,f,k,2*k-1);
		for(int i=0;i<k;i++) f[i]=f[i+k-1];
		sy[0]=y[0],sy2[0]=y[0]*y[0];
		for(int i=1;i<2*k;i++)
			sy[i]=sy[i-1]+y[i],sy2[i]=sy2[i-1]+y[i]*y[i];
		for(int i=0;i<k;i++)
		{
			lint s=2*(sx-S(sy,i,k-1+i)),s2=sx2+S(sy2,i,k-1+i);
			lint c=(lint)(-(db)s/(2*k)+0.5);
			ans=min(ans,k*c*c+s*c-2*f[i]+s2);
			c+=1,ans=min(ans,k*c*c+s*c-2*f[i]+s2);
			c-=2,ans=min(ans,k*c*c+s*c-2*f[i]+s2);
		}
		printf("%lld\n",ans);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Mys_C_K/article/details/82854796
FFT