[AH2017/HNOI2017] 礼物 解题报告 (FFT)
题目链接:
https://www.luogu.org/problemnew/show/P3723
题目:
我的室友最近喜欢上了一个可爱的小女生。马上就要到她的生日了,他决定买一对情侣手环,一个留给自己,一个送给她。每个手环上各有 n 个装饰物,并且每个装饰物都有一定的亮度。
但是在她生日的前一天,我的室友突然发现他好像拿错了一个手环,而且已经没时间去更换它了!他只能使用一种特殊的方法,将其中一个手环中所有装饰物的亮度增加一个相同的自然数 c(即非负整数)。并且由于这个手环是一个圆,可以以任意的角度旋转它,但是由于上面装饰物的方向是固定的,所以手环不能翻转。需要在经过亮度改造和旋转之后,使得两个手环的差异值最小。
在将两个手环旋转且装饰物对齐了之后,从对齐的某个位置开始逆时针方向对装饰物编号1,2,…,n,其中 n 为每个手环的装饰物个数, 第 1 个手环的 i 号位置装饰物亮度为 xi,第 2 个手环的 i 号位置装饰物亮度为 yi,两个手环之间的差异值为(参见输入输出样例和样例解释):
$\sum_{i=1}^{n} (x_i-y_i)^2$
麻烦你帮他计算一下,进行调整(亮度改造和旋转),使得两个手环之间的差异值最小,这个最小值是多少呢?
题解:
差异值=$\sum_{i=1}^{n}(a_i+x-b_i)^2$
$\sum_{i=1}^na_i^2+\sum_{i=1}^{n}b_i^2+nx^2+2x(\sum_{i=1}{n}a_i-\sum_{i=1}{n}b_i)-2\sum_{i=1}^{n}a_ib_i$
我们枚举$x(-m<=x<=m)$,发现除了最后一项都是定值
那么我们另最后一项最大即可
由于$a$,$b$其实都是可以旋转的,那么我们把$a$倍长
末项$=\sum_{i=x}^{n+x-1}a_ib_{i-x+1}$
再按照套路把$b$反向,$b_i=b_{n-i+1}$
末项$=\sum_{i=x}^{n-x+1}a_ib_{n-i+x}$
$=\sum_{i=1}^{n}a_{i-1+x}b_{n-i+1}$
这显然是一个卷积的形式,即把$a$与$b$卷起来的第$n+x$项
代码:
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<iostream>
#include<cmath>
using namespace std;
typedef double db;
typedef long long ll; const int N=1e6+;
const ll inf=1e18;
const db pi=acos(-1.0);
int r[N];
struct complex
{
db x,y;
complex (db xx=,db yy=) {x=xx;y=yy;}
}A[N],B[N];
complex operator + (complex a,complex b) {return complex(a.x+b.x,a.y+b.y);}
complex operator - (complex a,complex b) {return complex(a.x-b.x,a.y-b.y);}
complex operator * (complex a,complex b) {return complex(a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x);}
inline int read()
{
char ch=getchar();int s=,f=;
while (ch<''||ch>'') {if (ch=='-') f=-;ch=getchar();}
while (ch>=''&&ch<='') {s=(s<<)+(s<<)+ch-'';ch=getchar();}
return s*f;
}
void fft(int limit,complex *a,int type)
{
for (int i=;i<limit;i++) if (i<r[i]) swap(a[i],a[r[i]]);
for (int len=;len<limit;len<<=)
{
complex wn=complex(cos(pi/len),type*sin(pi/len));
for (int k=;k<limit;k+=(len<<))
{
complex w=complex(,);
for (int l=;l<len;l++,w=w*wn)
{
complex Nx=a[k+l],Ny=w*a[k+len+l];
a[k+l]=Nx+Ny;
a[k+len+l]=Nx-Ny;
}
}
}
}
int n,m;
int a[N],b[N];
int main()
{
ll a1=,b1=,a2=,b2=;
n=read();m=read();
for (int i=;i<=n;i++) a[i]=read(),a1+=a[i],a2+=a[i]*a[i];
for (int i=;i<=n;i++) b[i]=read(),b1+=b[i],b2+=b[i]*b[i]; for (int i=;i<=n;i++)
{
A[i].x=A[i+n].x=a[i];
B[i].x=b[n-i+];
} int limit=,l=;
while (limit<n+n+n) limit<<=,++l;
for (int i=;i<limit;i++) r[i]=(r[i>>]>>)|((i&)<<(l-)); fft(limit,A,);fft(limit,B,);
for (int i=;i<=limit;i++) A[i]=A[i]*B[i];
fft(limit,A,-);
for (int i=;i<=limit;i++) A[i].x=(ll)(A[i].x/limit+0.5); ll ans=inf;
for (int x=;x<=n;x++)
for (int z=-m;z<=m;z++)
ans=min(ans,a2+b2+n*z*z+2ll*z*(a1-b1)-2ll*(ll)A[x+n].x);
printf("%lld\n",ans);
return ;
}
最新文章
- [转]Pythoin中的Lambda表达式
- 关于《selenium2自动测试实战--基于Python语言》
- 初学Redis(1)——认识Redis
- [OpenCV] Basic data types - Matrix
- 【BZOJ 3223】文艺平衡树 模板题
- 【英语】Bingo口语笔记(45) - Pass系列
- bzoj3632
- 解决OOM小记
- Doubles water!!!!!!只会水题怎么破
- 在Eclipse下导入vlc-android并编译
- Entity Framework Code First约定
- Winform使用的一些常识
- Python学习_12_方法和类定制
- CUSTOM.PLL的使用
- AngularJS进阶(三十六)AngularJS项目开发技巧之利用Service&;Promise&;Resolve解决图片预加载问题(后记)
- fastDFS与java整合文件上传下载
- KVM宿主机上虚拟机动态添加新磁盘
- htmlunit+fastjson抓取酷狗音乐 qq音乐链接及下载
- 26.Hibernate-主键和映射.md
- iis日志分析软件及大文本切割软件下载