P3723 [AH2017/HNOI2017]礼物 [FFT]
P3723 [AH2017/HNOI2017]礼物
题目描述
给出两个数列, 长度都为;
定义差异值为
可以将任意数列加上任意自然数, 求最小差异值
数据范围
30%的数据满足
70%的数据满足
100%的数据满足
Solution
假设将其中一个加上
则差异值为
拆开得到
化简
由于可以改变项链装饰物顺序, 所以 不确定值
于是可以考虑枚举数列的所有旋转能够得到的顺序, 的值, 再去计算答案
复杂度
70pts get .
继续思考怎么优化
思考 .
思考.
思考.
思考.
思考.
思考.
发现最后一项是可以预处理的,
于是 pts get.
继续思考怎么优化
思考.
思考.
思考.
思考.
思考.
思考.
发现最后一项 :
反转数列,
可以变成卷积的形式 :即可用 求出多项式 :
又想到序列环是可以旋转的, 于是宣布这道题无解
因为已经拆开了环, 即将数列的长度延长为原来的2倍
若没有延长, 多项式最高次幂为 , 是由, 得到的
可以想到是有由 , 得到的
进而 是有由 , 得到的
于是得出结论, 表示旋转次后的
AC思路 :将y数组反转, 并且x延长1倍, 计算卷积, 最后直接计算取最优值即可
Addition
注意精度问题, double转long long需要 -exp
Code
#include<bits/stdc++.h>
#define reg register
const double Pi = acos(-1);
const int maxn = 1e6 + 10;
typedef long long ll;
int N, M, Len;
int rev[maxn];
struct Complex{
double x, y;
Complex(double x=0, double y=0):x(x), y(y) {}
} A[maxn], B[maxn];
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, b.x*a.y+a.x*b.y); }
void FFT(Complex *F, int opt){
for(reg int i = 0; i < Len; i ++)
if(i < rev[i]) std::swap(F[i], F[rev[i]]);
for(reg int p = 2; p <= Len; p <<= 1){
int l = p >> 1;
Complex delt(cos(Pi/l), opt*sin(Pi/l));
for(reg int i = 0; i < Len; i += p){
Complex w(1.0, 0.0);
for(reg int k = i; k < i + l; k ++){
Complex Temp = F[k+l] * w;
F[k+l] = F[k] - Temp;
F[k] = F[k] + Temp;
w = w * delt;
}
}
}
}
int main(){
scanf("%d%d", &N, &M);
for(reg int i = 1; i <= N; i ++) scanf("%lf", &A[i].x), A[i+N] = A[i];
for(reg int i = 1; i <= N; i ++) scanf("%lf", &B[i].x);
ll base = 0, base2 = 0;
for(reg int i = 1; i <= N; i ++) base += 1ll*A[i].x*A[i].x + 1ll*B[i].x*B[i].x;
for(reg int i = 1; i <= N; i ++) base2 += A[i].x-B[i].x;
for(reg int i = 1; i <= N>>1; i ++) std::swap(B[i], B[N-i+1]);
int bit_num = 0; Len = 1;
while(Len <= (N<<2)) Len <<= 1, bit_num ++;
for(reg int i = 0; i <= Len; i ++) rev[i] = (rev[i>>1]>>1) | ((i&1) << bit_num-1);
FFT(A, 1), FFT(B, 1);
for(reg int i = 0; i <= Len; i ++) A[i] = A[i] * B[i];
FFT(A, -1);
for(reg int i = 0; i <= Len; i ++) A[i].x /= Len*1.0;
ll Ans = 999999999999999999;
for(reg int i = N+1; i <= N<<1; i ++)
for(reg int b = -M; b <= M; b ++){
ll Temp = base + base2*2*b + 1ll*N*b*b - 2ll*(A[i].x-0.02);
Ans = std::min(Ans, Temp);
}
printf("%lld\n", Ans);
return 0;
}