板子
const int N = 4e5 + 10;
const double PI = acos(-1.0);
struct Complex{
double x, y;
Complex (){}
Complex (double u, double v){ x = u, y = v;}
Complex operator + (const Complex & other) const{ return Complex (x + other.x, y + other.y);}
Complex operator - (const Complex & other) const{ return Complex (x - other.x, y - other.y);}
Complex operator * (const Complex & other) const{ return Complex(x * other.x - y * other.y, x * other.y + y * other.x);}
}A[N], B[N];
int rev[N];
int FFT_pre(int n) //n = |A|+|B|
{
int lim = 1, L = 0;
while(lim <= n) lim <<= 1, L++;
for(int i = 0; i < lim; i++)
rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (L - 1));
return lim;
}
void FFT(Complex a[], int lim, int opt)
{
for(int i = 0; i < lim; i++)
if(i < rev[i])
swap(a[i], a[rev[i]]);
for(int i = 2; i <= lim; i <<= 1)
{
int tmp = i >> 1;
Complex wn = Complex(cos(2 * PI / i), opt * sin(2 * PI / i));
for(int j = 0; j < lim; j += i)
{
Complex w = Complex(1.0, 0.0);
for(int k = 0; k < tmp; k++)
{
Complex tmp1 = a[j + k];
Complex tmp2 = w * a[j + k + tmp];
a[j + k] = tmp1 + tmp2;
a[j + k + tmp] = tmp1 - tmp2;
w = w *wn;
}
}
}
if(opt == -1)
for(int i = 0; i < lim; i++)
a[i].x /= lim;
}
题目
[ZJOI2014]力
题意:给电荷量,求场强。即给
q
j
q_{j}
qj,
F
j
=
∑
i
=
1
j
−
1
q
i
∗
q
j
(
i
−
j
)
2
−
∑
i
=
j
+
1
n
q
i
∗
q
j
(
i
−
j
)
2
F_{j}=\sum_{i = 1}^{j-1}\frac{q_{i}*q_{j}}{(i-j)^{2}}-\sum_{i = j+1}^{n}\frac{q_{i}*q_{j}}{(i-j)^{2}}
Fj=∑i=1j−1(i−j)2qi∗qj−∑i=j+1n(i−j)2qi∗qj,
E
j
=
F
j
q
j
E_{j}=\frac{F_{j}}{q_{j}}
Ej=qjFj,求
E
j
E_{j}
Ej
思路:
E
j
=
∑
i
=
1
j
−
1
q
i
(
i
−
j
)
2
−
∑
i
=
j
+
1
n
q
i
(
i
−
j
)
2
E_{j}=\sum_{i = 1}^{j-1}\frac{q_{i}}{(i-j)^{2}}-\sum_{i = j+1}^{n}\frac{q_{i}}{(i-j)^{2}}
Ej=i=1∑j−1(i−j)2qi−i=j+1∑n(i−j)2qi
左边加一个j,右边减一个j,
=
∑
i
=
1
j
q
i
(
i
−
j
)
2
−
∑
i
=
j
n
q
i
(
i
−
j
)
2
=\sum_{i = 1}^{j}\frac{q_{i}}{(i-j)^{2}}-\sum_{i = j}^{n}\frac{q_{i}}{(i-j)^{2}}
=i=1∑j(i−j)2qi−i=j∑n(i−j)2qi
令
q
0
=
0
q_{0}=0
q0=0,
=
∑
i
=
0
j
q
i
(
i
−
j
)
2
−
∑
i
=
j
n
q
i
(
i
−
j
)
2
=\sum_{i = 0}^{j}\frac{q_{i}}{(i-j)^{2}}-\sum_{i = j}^{n}\frac{q_{i}}{(i-j)^{2}}
=i=0∑j(i−j)2qi−i=j∑n(i−j)2qi
令
k
=
i
−
j
k=i-j
k=i−j,
=
∑
i
=
0
j
q
i
(
i
−
j
)
2
−
∑
k
=
0
n
−
j
q
k
+
j
k
2
=\sum_{i = 0}^{j}\frac{q_{i}}{(i-j)^{2}}-\sum_{k = 0}^{n-j}\frac{q_{k+j}}{k^{2}}
=i=0∑j(i−j)2qi−k=0∑n−jk2qk+j
翻转q,令
Q
i
=
q
n
−
i
Q_{i} = q_{n-i}
Qi=qn−i,则
q
k
+
j
=
Q
(
n
−
j
)
−
i
q_{k+j}=Q_{(n-j)-i}
qk+j=Q(n−j)−i,
=
∑
i
=
0
j
q
i
(
i
−
j
)
2
−
∑
k
=
0
n
−
j
Q
(
n
−
j
)
−
i
k
2
=\sum_{i = 0}^{j}\frac{q_{i}}{(i-j)^{2}}-\sum_{k = 0}^{n-j}\frac{Q_{(n-j)-i}}{k^{2}}
=i=0∑j(i−j)2qi−k=0∑n−jk2Q(n−j)−i
卷就完事了。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long LL;
const int N = 4e5 + 10;
const double PI = acos(-1.0);
struct Complex{
double x, y;
Complex (){}
Complex (double u, double v){ x = u, y = v;}
Complex operator + (const Complex & other) const{ return Complex (x + other.x, y + other.y);}
Complex operator - (const Complex & other) const{ return Complex (x - other.x, y - other.y);}
Complex operator * (const Complex & other) const{ return Complex(x * other.x - y * other.y, x * other.y + y * other.x);}
}a[N], b[N], c[N];
int rev[N];
void FFT(Complex a[], int lim, int opt)
{
for(int i = 0; i < lim; i++)
if(i < rev[i])
swap(a[i], a[rev[i]]);
for(int i = 2; i <= lim; i <<= 1)
{
int tmp = i >> 1;
Complex wn = Complex(cos(2 * PI / i), opt * sin(2 * PI / i));
for(int j = 0; j < lim; j += i)
{
Complex w = Complex(1.0, 0.0);
for(int k = 0; k < tmp; k++)
{
Complex tmp1 = a[j + k];
Complex tmp2 = w * a[j + k + tmp];
a[j + k] = tmp1 + tmp2;
a[j + k + tmp] = tmp1 - tmp2;
w = w *wn;
}
}
}
if(opt == -1)
for(int i = 0; i < lim; i++)
a[i].x /= lim;
}
int main()
{
int n;
scanf("%d", &n);
for(int i = 1; i <= n; i++)
scanf("%lf", &a[i].x);
for(int i = 1; i <= n; i++)
{
b[i].x = (double)(1.0 / i / i);
c[n - i].x = a[i].x;
}
int lim = 1, L = 0;
while(lim <= (n << 1)) lim <<= 1, L++;
for(int i = 0; i < lim; i++)
rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (L - 1));
FFT(a, lim,1), FFT(b, lim, 1),FFT(c, lim, 1);
for(int i = 0; i < lim; i++)
a[i] = a[i] * b[i], c[i] = c[i] * b[i];
FFT(a, lim, -1), FFT(c, lim, -1);
for(int i = 1; i <= n; i++)
printf("%.3lf\n", a[i].x - c[n - i].x);
return 0;
}
[AH2017/HNOI2017]礼物
题意:数组
a
i
a_{i}
ai、
b
i
b_{i}
bi,可以对
a
i
a_{i}
ai整体加一个正整数,也可以对
b
i
b_{i}
bi整体加一个正整数,然后进行轮转,求
∑
i
=
1
n
(
a
i
−
b
i
)
2
\sum_{i=1}^{n}(a_{i}-b_{i})^{2}
∑i=1n(ai−bi)2 的最小值。
思路:
整体加值的操作可以看出在其中一个数组上进行加减,于是所求值可以写成
∑
i
=
1
n
(
a
i
+
x
−
b
i
)
2
=
∑
i
=
1
n
a
i
2
+
∑
i
=
1
n
b
i
2
+
n
x
2
+
2
x
∑
i
=
1
n
a
i
−
2
x
∑
i
=
1
2
b
i
−
2
∑
i
=
1
n
a
i
b
i
\sum_{ i=1}^{n}(a_{i}+x-b_{i})^{2}=\sum_{i=1}^{n}a_{i}^{2}+\sum_{i=1}^{n}b_{i}^{2}+nx^{2}+2x\sum_{i=1}^{n}a_{i}-2x\sum_{i=1}^{2}b_{i}-2\sum_{i=1}^{n}a_{i}b_{i}
i=1∑n(ai+x−bi)2=i=1∑nai2+i=1∑nbi2+nx2+2xi=1∑nai−2xi=1∑2bi−2i=1∑naibi。发现只需求
n
x
2
−
2
∑
i
=
1
n
a
i
b
i
nx^{2}-2\sum_{i=1}^{n}a_{i}b_{i}
nx2−2∑i=1naibi的最小值就可以了,而
n
x
2
nx^{2}
nx2与
2
∑
i
=
1
n
a
i
b
i
2\sum_{i=1}^{n}a_{i}b_{i}
2∑i=1naibi两项的变化没有关系,可以分开来看。
对于
∑
i
=
1
n
a
i
b
i
\sum_{i=1}^{n}a_{i}b_{i}
∑i=1naibi,翻转
a
i
a_{i}
ai得到
∑
i
=
1
n
a
n
−
i
b
i
\sum_{i=1}^{n}a_{n-i}b_{i}
∑i=1nan−ibi,倍长
b
i
b_{i}
bi以后FFT,求
x
n
x^{n}
xn项以后最小的即可。
对于
n
x
2
nx^{2}
nx2,枚举[-m, m]中每一个值就可以了。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long LL;
const int N = 4e5 + 10;
const double PI = acos(-1.0);
struct Complex{
double x, y;
Complex (){}
Complex (double u, double v){ x = u, y = v;}
Complex operator + (const Complex & other) const{ return Complex (x + other.x, y + other.y);}
Complex operator - (const Complex & other) const{ return Complex (x - other.x, y - other.y);}
Complex operator * (const Complex & other) const{ return Complex(x * other.x - y * other.y, x * other.y + y * other.x);}
}A[N], B[N];
int rev[N];
int FFT_pre(int n)
{
int lim = 1, L = 0;
while(lim <= n) lim <<= 1, L++;
for(int i = 0; i < lim; i++)
rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (L - 1));
return lim;
}
void FFT(Complex a[], int lim, int opt)
{
for(int i = 0; i < lim; i++)
if(i < rev[i])
swap(a[i], a[rev[i]]);
for(int i = 2; i <= lim; i <<= 1)
{
int tmp = i >> 1;
Complex wn = Complex(cos(2 * PI / i), opt * sin(2 * PI / i));
for(int j = 0; j < lim; j += i)
{
Complex w = Complex(1.0, 0.0);
for(int k = 0; k < tmp; k++)
{
Complex tmp1 = a[j + k];
Complex tmp2 = w * a[j + k + tmp];
a[j + k] = tmp1 + tmp2;
a[j + k + tmp] = tmp1 - tmp2;
w = w *wn;
}
}
}
if(opt == -1)
for(int i = 0; i < lim; i++)
a[i].x /= lim;
}
int a[N], b[N];
int main()
{
int n, m;
scanf("%d%d", &n, &m);
for(int i = 1;i <= n; i++) scanf("%d", &a[i]);
for(int i = 1; i <= n; i++) scanf("%d", &b[i]);
LL sum1 = 0, sum2 = 0;
for(int i = 1; i <= n; i++)
{
A[n - i + 1].x = a[i];
B[i].x = B[i + n].x = b[i];
sum1 += a[i] * a[i] + b[i] * b[i];
sum2 += a[i] - b[i];
}
int lim = FFT_pre(n * 3);
FFT(A, lim, 1);
FFT(B, lim, 1);
for(int i = 0; i < lim; i++) A[i] = A[i] * B[i];
FFT(A, lim, -1);
LL ans = 1e18;
for(int i = 1; i <= n; i++)
for(int j = -m; j <= m; j++)
ans = min(ans, sum1 + 2 * j * sum2 + n * j * j - 2 * (LL)(A[i + n].x + 0.5));
cout << ans;
return 0;
}