P3723 [AH2017/HNOI2017]礼物
P3723 [AH2017/HNOI2017]礼物
题目要求:
拿到一看,30分暴力分肯定有——直接枚举错多少位与添加多少亮度。
然后,设添加亮度为
则原式为
即:
展开:
由于不论错多少位,
设
即转化为
那么再对这个式子化简:
还是拆开:
而前面那个
求
乍一看,有点卷积的样子。。。
没错!就是卷积!
但是求和很烦。。。
没关系,我们将数列{
稳稳的卷积。。。
于是,我们将反转的数列{
注:
-
其实可以不用从第
n+1 到第2n 项,因为这里面最大,一定是第1 到第2n 项的最大。 -
FFT因为要转到
double 在转回long long ,有精度误差!所以eps 应该开到1e-2 -
求
t 时,要在t-1 ,t ,t+1 中选出使nt^2-2t\sum_{i=1}^{n}(x_i-y_i) 取最小值的t 。
到此,我们的思路结束。
但是卷积怎么求?
主角登场——FFT,快速傅里叶变换。
说白了就是在
然后我们并不需要知道什么推导过程啦,蝴蝶变换啦什么乱七八糟的玩意,考到了,基本上是推导很烦,但是FFT直接上板子即可的那种板子题。
FFT都是板子题!——巨神CYZ
附代码:
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cmath>
#define MAXN (1<<18)
using namespace std;
int n,m,x[MAXN],y[MAXN];
long long add,s1=0,s2=0,s;
namespace FFT{//用namespace封装的板子
int n,l,rev[MAXN];
long long answer=2147483646,ans[MAXN];
struct node{
double r,i;
node operator +(const node &a)const{return (node){r+a.r,i+a.i};}
node operator -(const node &a)const{return (node){r-a.r,i-a.i};}
node operator *(const node &a)const{return (node){r*a.r-i*a.i,r*a.i+i*a.r};}
}a[MAXN],b[MAXN],d[MAXN];
void DFT(node *a,int f){
for(int i=0;i<l;i++)d[i]=a[rev[i]];
for(int i=0;i<l;i++)a[i]=d[i];
for(int i=2;i<=l;i<<=1){
node wi=(node){cos(2.00*M_PI/i),f*sin(2.00*M_PI/i)};
for(int k=0;k<l;k+=i){
node w=(node){1.00,0.00},x,y;
for(int j=0;j<i/2;j++){
x=a[k+j];y=w*a[k+j+i/2];
a[k+j]=x+y;a[k+j+i/2]=x-y;
w=w*wi;
}
}
}
if(f==-1)
for(int i=0;i<l;i++)a[i].r/=l;
}
void FFT(){
DFT(a,1);DFT(b,1);
for(int i=0;i<l;i++)a[i]=a[i]*b[i];
DFT(a,-1);
}
void init(int x){
for(n=l=1;l<x;l<<=1)n++;
l<<=1;
for(int i=0;i<l;i++)
for(int j=0,t=i;j<n;j++,t>>=1){rev[i]<<=1;rev[i]|=t&1;}
}
void DSC(int len){
int l1=0,l2=0;
for(int i=1;i<=len*2;i++){a[l1].r=x[i];a[l1++].i=0.00;}
for(int i=1;i<=len;i++){b[l2].r=y[i];b[l2++].i=0.00;}
reverse(a,a+l1);reverse(b,b+l2);
init(max(l1,l2));
FFT();
for(int i=1;i<=l;i++)ans[i]=(long long)(a[i-1].r+0.5);
for(int i=1;i<=l;i++)answer=min(answer,s2-ans[i]*2);
printf("%lld\n",answer+s);
}
}
inline int read(){//读优
int date=0,w=1;char c=0;
while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
return date*w;
}
void init(){//预处理
s=2147483646;
n=read();m=read();
for(int i=1;i<=n;i++)x[i+n]=x[i]=read();
for(int i=1;i<=n;i++)y[n-i+1]=read();
for(int i=1;i<=n;i++){
s1+=x[i]-y[i];
s2+=x[i]*x[i]+y[i]*y[i];
}
add=(long long)((double)-s1*1.000/n+0.5);
for(int i=-1;i<=1;i++)s=min(s,(n*(add+i)*(add+i)+2*s1*(add+i)));
}
int main(){//主函数So easy!
init();
FFT::DSC(n);
return 0;
}