[Hnoi2017]礼物,bzoj4827,FFT

正题

      看题,发现有两个操作:

      1.把第二个序列旋转。

      2.把第一个序列整体+c。

      因为旋转只用一个旋转就够了。

      发现什么。

      (a-b)^2=a^2+b^2-2ab

      所以使xy的和最大即可。

      假设f_i表示第二个序列向有旋转i位的价值。

      那么就有f_i=\sum_{j=1}^n a_j*b_{i+j}

      不是卷积的形式。

      那么怎么办,让F_{n+i}=f_iA_{n-i}=a_i

      那么就有F_{n+i}=\sum_{j=1}^n A_{n-j}*b_{i+j}

      又因为(n-j)+(i+j)=n+i

      所以可以直接用卷积来做。

      其实就相当于把A反过来。

      然后求F_n\to F_{n+n-1}之间的最小值。

      那么现在有个问题就是要整体+c。

      很好做,我们枚举一个c,把它加给第一个序列.

      会发现 \\((a+c)+b)^2=(a+c)^2+b^2-2b(a+c) \\=(a+c)^2+b^2-2(ab+bc)

      那么这就很有趣了,我们现在用FFT来确定了ab最大,又可以通过枚举来知道bc的大小。

      那么每次算出平方和再减去ab+bc的两倍,取一个最小值就可以了。

#include
#include
#include
#include
#include
using namespace std;

struct complex{
	double x,y;
    complex (double xx=0,double yy=0){x=xx,y=yy;}
    complex operator-(const complex b)const {return (complex){x-b.x,y-b.y};}
    complex operator+(const complex b)const {return (complex){x+b.x,y+b.y};}
    complex operator*(const complex b)const {return (complex){x*b.x-y*b.y,x*b.y+b.x*y};}
}a[300010],b[300010];
int d1[100010],d2[100010];
int n,m;
const double Pi=acos(-1.0);
int where[300010];
int limit,l;

void dft(complex *now,int idft){
    for(int i=0;i=0;i--) scanf("%d",&d1[i]),a[i].x=d1[i];
	for(int i=1;i<=n;i++) scanf("%d",&d2[i]),b[i+n].x=b[i].x=d2[i],sum+=d2[i];
	limit=1,l=0;
	while(limit<3*n+1) limit*=2,l++;
	for(int i=0;i>1]>>1) | ((i&1)<<(l-1));
	dft(a,1);
	dft(b,1);
	for(int i=0;i<=limit;i++) a[i]=a[i]*b[i];
	dft(a,-1);
	int ans=2147483647;
	int mmax=0;
	for(int i=n;i<=2*n-1;i++)
		mmax=max(mmax,(int)(a[i].x/limit+0.5));
	int now=0,dat=0;
	for(int i=0;i

 

你可能感兴趣的:([Hnoi2017]礼物,bzoj4827,FFT)