首页 > 笔记 > FFT应用总结

FFT应用总结

只是一些简单的应用,更难一点的还没写完。。

感觉在学校没啥效率,整天瞎考试

bzoj3527

题意

给出$n$个$q_i$,且

$$F_j = \sum_{i< j}{q_iq_j\over (i – j)^2}-\sum_{i>j}{q_iq_j\over (i – j)^2}$$

求$E_i = {F_i\over q_i}$

题解

首先把$i,j$调一下,看着太难受了

$$F_i = \sum_{j< i}{q_iq_j\over (j – i)^2}-\sum_{j>i}{q_iq_j\over (j – i)^2}$$

这样就可以化式子了
$$
\begin{aligned}
E_i &= {F_i \over q_i}\\
&=\sum_{j< i}{q_j\over (j – i)^2}-\sum_{j>i}{q_j\over (j – i)^2}\\
&=\sum_{j=1}^{i-1}{q_j\over (j – i)^2}-\sum_{j=i+1}^n{q_j\over (j – i)^2}\\
&设 g_i = {1\over i^2}\;\;\; f_i = q_i\\
E_i &=\sum_{j=1}^{i-1}{f_jg_{i – j}}-\sum_{j=i+1}^n{f_jg_{j – i}}\\
\end{aligned}
$$

左边的式子显然是个卷积,现在看下右边的式子

$$\sum_{j = i+1}^nf_jg_{j – i}$$

可以换个元

$$\sum_{j + i = i+1}^nf_{j + i}g_{j + i – i}$$

等式两边同时减掉一个$i$。($g_0 = 0$可以直接化)

$$\sum_{j = 0}^{n -i}f_{j+i}g_j$$

再换元

$$\sum_{n-i-j=0}^{n-i}f_{n-i-j+i}g_{n-i-j}$$

化成

$$\sum_{j=0}^{n-i}f_{n-j}g_{n-i-j}$$

设$t = n-i$

$$\sum_{j = 0}^tf_{n-j}g_{t-j}$$

设$f’_i = f_{n-i}$

$$\sum_{j=0}^t f’_jg_{t-j}$$

。。

#include <cstdio>
#include <algorithm>
#include <cmath>
using namespace std;
const double pi=acos(-1.0);
const int N = 400010;
int n, m, r[N];
struct complex {
    double x, y;
    complex (double xx = 0, double yy = 0) {
        x = xx, y = yy;
    }
}a[N], b[N], o[N], a_o[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); }
void init(int n) {
    double t = 2 * pi / n;
    for (int i = 0; i <= n; ++i) {
        o[i] = complex(cos(2.0 * pi * i / n), sin(2.0 * pi * i / n));
        a_o[i] = complex(cos(2.0 * pi * i / n),-1 * sin(2.0 * pi * i / n));
    }
}
void fft(int n, complex *a, complex *w)
{
    for (int i = 0; i < n; ++i)
        if (i < r[i])
            swap(a[i], a[r[i]]);
    for (int i = 2; i <= n; i <<= 1) {
        int m = i >> 1;
        for (int j = 0; j < n;j += i)
            for (int k = 0; k < m; ++k) {
                complex t = a[j + m + k] * w[n / i * k];
                a[j + m + k] = a[j + k] - t;
                a[j + k] = a[j + k] + t;
            }
    }
}
double ans[N], q[N];
main() {
    static int n,m,fn,l=0;
    scanf("%d", &n);
    for (int i = 1; i <= n; ++i) scanf("%lf", &q[i]);

    a[0].x = 0;
    for (int i = 1; i <= n; ++i) a[i].x = q[i];
    b[0].x = 0;
    for (int i = 1; i <= n; ++i) b[i].x = 1.0 / i / i;
    fn = 1;
    while (fn <= n * 2) fn <<= 1, ++l;
    for (int i = 0; i < fn; ++i)
        r[i] = (r[i >> 1] >> 1) | ((i & 1) << (l - 1));
    init(fn);
    fft(fn, a, o);
    fft(fn, b, o);
    for (int i = 0; i <= fn; ++i) a[i] = a[i] * b[i];
    fft(fn, a, a_o);
    for (int i = 0; i <= n; ++i)
        ans[i] = a[i].x / fn;

    for (int i = 0; i <= n; ++i) a[i].x = q[n - i], a[i].y = 0;
    for (int i = n + 1; i <= fn; ++i) a[i].x = 0, a[i].y = 0;
    b[0].x = 0, b[0].y = 0;
    for (int i = 1; i <= n; ++i) b[i].x = 1.0 / i / i, b[i].y = 0;
    for (int i = n + 1; i <= fn; ++i) b[i].x = 0, b[i].y = 0;
    fft(fn, a, o);
    fft(fn, b, o);
    for (int i = 0; i <= fn; ++i) a[i] = a[i] * b[i];
    fft(fn, a, a_o);
    for (int i = 1; i <= n; ++i)
        ans[i] -= a[n - i].x / fn;
    for (int i = 1; i <= n; ++i)
        printf("%.2lf\n", ans[i]);
}

bzoj 2194

题意

$$c_k=\sum_{k\leq i< n}a_ib_{i-k}$$

题解

化式子吧。。
$$
\large
\begin{aligned}
c_k &= \sum_{k \leq i \leq n-1}a_ib_{i-k}\\
&= \sum_{0\leq i-k \leq n-k-1} a_ib_{i-k}\\
&= \sum_{0 \leq j \leq n-k-1} a_{j+k}b_j \;\;\;\;(j=i-k)\\
& 设 \; N=n-k-1,c’_N=c_k\\
c’_N &= \sum_{0 \leq j\leq N}a_{n-1-(N-j)}b_j\\
& 设 \; a’_{N-j}=a_{n-1-(N-j)},a’_{i}=a_{n-1-i}\\
c’_N &= \sum_{0 \leq j\leq N}a’_{N-j}b_j
\end{aligned}
$$

。。

#include <cstdio>
#include <algorithm>
#include <cmath>
using namespace std;
const double pi=acos(-1.0);
const int N = 400010;
int n, m, r[N];
struct complex {
    double x, y;
    complex (double xx = 0, double yy = 0) {
        x = xx, y = yy;
    }
}a[N], b[N], o[N], a_o[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); }
void init(int n) {
    double t = 2 * pi / n;
    for (int i = 0; i <= n; ++i) {
        o[i] = complex(cos(2.0 * pi * i / n), sin(2.0 * pi * i / n));
        a_o[i] = complex(cos(2.0 * pi * i / n),-1 * sin(2.0 * pi * i / n));
    }
}
void fft(int n, complex *a, complex *w)
{
    for (int i = 0; i < n; ++i)
        if (i < r[i])
            swap(a[i], a[r[i]]);
    for (int i = 2; i <= n; i <<= 1) {
        int m = i >> 1;
        for (int j = 0; j < n;j += i)
            for (int k = 0; k < m; ++k) {
                complex t = a[j + m + k] * w[n / i * k];
                a[j + m + k] = a[j + k] - t;
                a[j + k] = a[j + k] + t;
            }
    }
}
double p[N], q[N], ans[N];
main() {
    static int n,m,fn,l=0;
    scanf("%d", &n);
    for (int i = 0; i < n; ++i) scanf("%lf%lf", &p[i], &q[i]);

    for (int i = 0; i <= n; ++i) a[i].x = p[n - i - 1];
    for (int i = 0; i <= n; ++i) b[i].x = q[i];
    fn = 1;
    while (fn <= n * 2) fn <<= 1, ++l;
    for (int i = 0; i < fn; ++i)
        r[i] = (r[i >> 1] >> 1) | ((i & 1) << (l - 1));
    init(fn);
    fft(fn, a, o);
    fft(fn, b, o);
    for (int i = 0; i <= fn; ++i)
        a[i] = a[i] * b[i];
    fft(fn, a, a_o);
    for (int i = 0; i < n; ++i)
        ans[n - i - 1] = a[i].x / fn;
    for (int i = 0; i < n ; ++i)
        printf("%d\n", (int)(ans[i] + 0.5));
}

bzoj 3771

题意

给出$n$个物品,价值为别为$X_i$且各不相同,现在可以取$1$个、$2$个或$3$个,问每种价值和有几种情况?

*顺序不同算一种

题解

构造三个生成函数,系数是这个数出现了几次。$A$表示每种物品取一个的情况,$B$表示每种物品取二个的情况,$C$表示每种物品取三个的情况。

也就是对于每种物品价值$X_i$,A[Xi]++,B[2 * Xi]++,C[3 * Xi]++

如果取$1$个物品,答案就是$A$。

如果取$2$个物品,$A^2$中有重复的$(X_i,X_i)$的情况,所以答案为$A^2-B$。

如果取$3$个物品,$A^3$中可能有$(X_i,X_i,X_i)(X_i,X_i,Y_i)(X_i,Y_i,X_i)(Y_i,X_i,X_i)$这几种重复的情况,而$A\times B$能够求出所有形容$(X_i,X_i,X_i)$和$(X_i,Y_i,Y_i)$的情况数。$(X_i,X_i,Y_i)(X_i,Y_i,X_i)(Y_i,X_i,X_i)$总的情况数=$(X_i,Y_i,Y_i)\times 3$,而$A\times B\times3$又会多减去了两次$(X_i,X_i,X_i)$,所以要用$C$加回来。所以答案为$A^3-3\times B\times A+2\times C$。又由于顺序不同算一种情况,因为每种物品价值都不一样,情况(2)/2,情况(3)/6。

总答案就是

$${A^3(x)-3A(x)·B(x)+2C(x)\over 6}+{A^2(x)-B(x)\over 2}+A(x)$$

注意可以一直用点值表达式形式算。

#include <cstdio>
#include <algorithm>
#include <cmath>
using namespace std;
const double pi=acos(-1.0);
const int N = 262194;
int n, m, r[N];
struct complex {
    double x, y;
    complex (double xx = 0, double yy = 0) {
        x = xx, y = yy;
    }
}a[N], b[N], c[N], o[N], a_o[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); }
complex operator / (complex a,double b) { return complex(a.x / b, a.y / b); }
void init(int n) {
    double t = 2 * pi / n;
    for (int i = 0; i <= n; ++i) {
        o[i] = complex(cos(2.0 * pi * i / n), sin(2.0 * pi * i / n));
        a_o[i] = complex(cos(2.0 * pi * i / n),-1 * sin(2.0 * pi * i / n));
    }
}
void fft(int n, complex *a, complex *w)
{
    for (int i = 0; i < n; ++i)
        if (i < r[i])
            swap(a[i], a[r[i]]);
    for (int i = 2; i <= n; i <<= 1) {
        int m = i >> 1;
        for (int j = 0; j < n;j += i)
            for (int k = 0; k < m; ++k) {
                complex t = a[j + m + k] * w[n / i * k];
                a[j + m + k] = a[j + k] - t;
                a[j + k] = a[j + k] + t;
            }
    }
}
main() {
    static int n, m, fn, x, l=0;
    scanf("%d", &n);
    for (int i = 1; i <= n; ++i) {
        scanf("%d", &x);
        a[x].x += 1, b[x * 2].x += 1, c[x * 3].x += 1;
        m = max(m, x * 3);
    }
    fn = 1;
    while (fn <= m + m) fn <<= 1, ++l;
    for (int i = 0; i < fn; ++i)
        r[i] = (r[i >> 1] >> 1) | ((i & 1) << (l - 1));
    init(fn);
    fft(fn, a, o);
    fft(fn, b, o);
    fft(fn, c, o);
    complex n2, n3, n6;
    n2.x = 2, n2.y = 0;
    n3.x = 3, n3.y = 0;
    n6.x = 6, n6.y = 0;
    for (int i = 0; i <= fn; ++i)
        a[i] = ((a[i] * a[i] * a[i]) - n3 * a[i] * b[i] + n2 * c[i]) / 6.0 + (a[i] * a[i] - b[i]) / 2.0 + a[i];
    fft(fn, a, a_o);
    for (int i = 1; i <= m + m; ++i) {
        long long ans = (long long) (a[i].x / fn + 0.5);
        if (ans) printf("%d %d\n", i, ans);
    }
}

bzoj 3513

题解

因为$a_i$的范围很小,可以搞个权值多项式,$A_i$表示长度为$i$的木棒出现了多少次

现在考虑求一个$B_i$表示两根木棒拼起来的权值多项式,显然

$$B_i = \sum A_j \times A_{i-j}$$

这是一个卷积的形式,直接fft求解

然后发现这样会出现自己和自己拼起来的情况,直接减掉即可

现在考虑求一下答案的补集,就是不能拼成三角形的情况,再拿1减掉就是答案。

我们对$B$求一个前缀和,那么$B_i$就表示了两根木棒拼起来小于等于$i$的有多少个

那么答案的补集就是$B_i\times A_i$,就是原始长度为$i$的个数乘上拼起来长度小于等于它的个数

因为能正着和倒着拼,所以要除2。最后别忘了除$C_n^3$,我们求的是概率。

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
int inline read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
const double pi=acos(-1.0);
const int N = 300010;
int n, m, r[N];
struct complex {
    double x, y;
    complex (double xx = 0, double yy = 0) {
        x = xx, y = yy;
    }
}a[N], o[N], a_o[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); }
void init(int n) {
    double t = 2 * pi / n;
    for (int i = 0; i <= n; ++i) {
        o[i] = complex(cos(2.0 * pi * i / n), sin(2.0 * pi * i / n));
        a_o[i] = complex(cos(2.0 * pi * i / n),-1 * sin(2.0 * pi * i / n));
    }
}
void fft(int n, complex *a, complex *w) {
    for (int i = 0; i < n; ++i)
        if (i < r[i])
            swap(a[i], a[r[i]]);
    for (int i = 2; i <= n; i <<= 1) {
        int m = i >> 1;
        for (int j = 0; j < n;j += i)
            for (int k = 0; k < m; ++k) {
                complex t = a[j + m + k] * w[n / i * k];
                a[j + m + k] = a[j + k] - t;
                a[j + k] = a[j + k] + t;
            }
    }
}
int x, ton[N];
long long te[N];
main() {
//  freopen("da.txt","r",stdin);
    static int n, fn, l, T;
    T = read();
    while (T--) {
        scanf("%d", &n);
        l = 0;
        for (int i = 0; i <= fn; ++i) {
            r[i] = 0;
            a[i].x = 0, a[i].y = 0;
        }
        int mx = 0;
        memset(ton, 0, sizeof ton);
        for (int i = 1; i <= n; ++i)
            x = read(), a[x].x += 1.0,
            ton[x]++, mx = max(mx, x);
        fn = 1;
        while (fn <= mx + mx) fn <<= 1, ++l;
        for (int i = 0; i < fn; ++i)
            r[i] = (r[i >> 1] >> 1) | ((i & 1) << (l - 1));
        init(fn);
        fft(fn, a, o);
        for (int i = 0; i <= fn; ++i)
            a[i] = a[i] * a[i];
        fft(fn, a, a_o);
        for (int i = 0; i <= mx; ++i)
            te[i] = (long long)(a[i].x / (double)fn + 0.5);
        for (int i = 0; i <= mx >> 1; ++i)
            te[i<<1] -= ton[i];
        for (int i = 1; i <= mx; ++i)
            te[i] += te[i - 1];
        double ans = 0;
        for (int i = 1; i <= mx; ++i)
            ans += te[i] * ton[i];
        double C = n * (n - 1.0) * (n - 2.0) / 6.0;
        ans /= 2.0;
        printf("%.7lf\n", 1.0 - ans / C);
    }
}

bzoj 4259

题解

首先我们定义一个字符串的距离函数,对于两个长度都是$n$的字符串$A,B$,定义他们的距离为

$$dis(A,B) = \sum_{i = 0}^{n-1}(A_i – B_i)^2 [A_i != *][B_i!=*]$$

假如我们把所有星号都约定成$0$的话

$$dis(A,B) = \sum_{i = 0}^{n – 1}(A_i-B_i)^2A_iB_i$$

对于题目的话,首先发现题面里面写到$1\leq m\leq n\leq 300000$,也就是说第二个串要比第一个串要长

那么我们可以枚举第二个串的结尾位置来匹配,定义函数$f_i = dis(A,B[i – m + 1,i])$,那么

$$f_i = \sum_{i = 0}^{m – 1} (A_j – B_{i – m + 1 + j})^2A_jB_{i – m + 1 + j}$$

也就是,$f_i = 0$的时候表明$B$的这个子串和$A$成功匹配了

但是我们想凑出个卷积该怎么办呢?首先式子里面应该有个$i – j$,要构造出来一个的话必须把一个串翻转一下,那我们就把$A$串翻转一下。还有就是$B$的下标有点乱,需要化简一下。我们现在是一个枚举长度$m$,但是我们可以在$A$后面添加很多个$0$,让它变成一个枚举$i$的式子,这样就非常符合卷积的形式了:
$$
\begin{aligned}
f_i &= \sum_{j = 0}^i(A_j – B_{i – j})^2A_jB_{i – j}\\
&=\sum_{j = 0}^i(A_j^2-2A_jB_{i – j} + B_{i – j}^2)A_jB_{i – j}\\
&=\sum_{j = 0}^iA_j^3B_{i – j}-2\sum_{j = 0}^iA_j^2B_{i – j}^2+\sum_{j = 0}^iA_jB_{i – j}^3\\
\end{aligned}
$$

。。

#include <cstdio>
#include <algorithm>
#include <cmath>
using namespace std;
const double pi=acos(-1.0);
const int N = 1048576;
int n, m, r[N];
struct complex {
    double x, y;
    complex (double xx = 0, double yy = 0) {
        x = xx, y = yy;
    }
}a[N], b[N], c[N], o[N], a_o[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); }
void init(int n) {
    double t = 2 * pi / n;
    for (int i = 0; i <= n; ++i) {
        o[i] = complex(cos(2.0 * pi * i / n), sin(2.0 * pi * i / n));
        a_o[i] = complex(cos(2.0 * pi * i / n),-1 * sin(2.0 * pi * i / n));
    }
}
void fft(int n, complex *a, complex *w) {
    for (int i = 0; i < n; ++i)
        if (i < r[i])
            swap(a[i], a[r[i]]);
    for (int i = 2; i <= n; i <<= 1) {
        int m = i >> 1;
        for (int j = 0; j < n; j += i)
            for (int k = 0; k < m; ++k) {
                complex t = a[j + m + k] * w[n / i * k];
                a[j + m + k] = a[j + k] - t;
                a[j + k] = a[j + k] + t;
            }
    }
}
int p[N], q[N], ans[N], top;
char s1[N], s2[N];
int tr(int x) { return x * x * x; }
int sq(int x) { return x * x; }
main() {
    static int n, m, fn, l = 0;
    scanf("%d%d", &m, &n);
    scanf("%s%s", s1, s2);
    n--, m--;
    fn = 1;
    while (fn <= n + m) fn <<= 1, ++l;
    for (int i = 0; i < fn; ++i)
        r[i] = (r[i >> 1] >> 1) | ((i & 1) << (l - 1));
    init(fn);
    for (int i = 0, j = m; i < j; i++, j--) swap(s1[i], s1[j]);
    for (int i = 0; i <= m; ++i) if (s1[i] != '*') p[i] = s1[i] - 'a' + 1;
    for (int i = 0; i <= n; ++i) if (s2[i] != '*') q[i] = s2[i] - 'a' + 1;
    for (int i = 0; i <= fn; ++i) a[i].x = tr(p[i]), a[i].y = 0;
    for (int i = 0; i <= fn; ++i) b[i].x = q[i], b[i].y = 0;
    fft(fn, a, o), fft(fn, b, o);
    for (int i = 0; i <= fn; ++i) c[i] = c[i] + a[i] * b[i];
    for (int i = 0; i <= fn; ++i) a[i].x = p[i], a[i].y = 0;
    for (int i = 0; i <= fn; ++i) b[i].x = tr(q[i]), b[i].y = 0;
    fft(fn, a, o), fft(fn, b, o);
    for (int i = 0; i <= fn; ++i) c[i] = c[i] + a[i] * b[i];
    complex two; two.x = 2, two.y = 0;
    for (int i = 0; i <= fn; ++i) a[i].x = sq(p[i]), a[i].y = 0;
    for (int i = 0; i <= fn; ++i) b[i].x = sq(q[i]), b[i].y = 0;
    fft(fn, a, o), fft(fn, b, o);
    for (int i = 0; i <= fn; ++i) c[i] = c[i] - a[i] * b[i] * two;
    fft(fn, c, a_o);
    for (int i = 0; i <= fn; ++i) c[i].x = c[i].x / fn;
    for (int i = m; i <= n; ++i) if (c[i].x < 0.5) ans[++top] = i - m + 1;
    printf("%d\n", top);
    for (int i = 1; i < top; ++i) printf("%d ", ans[i]);
    if (top) printf("%d", ans[top]);
}

bzoj3509

题解

首先简单化下式子,发现$2A_j=A_i+A_k$

也就是说一个数在两边选两个数使得两数的和为这个数的两倍。

这样对这个数两边的数放到权值生成函数里面,fft一下再找这个数的两倍就可以了。

发现太慢了,$O(n^2\log n)$(这里就把$a_i$最大值也设成$n$了,懒)

这样就可以想到分块的思想,对于块内的暴力一下,块外的fft求下,就可以了。

算下复杂度是$O(\sqrt n \;n\log n+\sqrt n\; n)$

(需要有优越的调参技术

#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
using namespace std;
const double pi=acos(-1.0);
const int N = 70010;
const int M = 100010;
#define getchar() (S == T && (T = (S = BB) + fread(BB, 1, 1 << 15, stdin), S == T) ? EOF : *S++)
using namespace std;
char BB[1 << 15], *S = BB, *T = BB;
int inline read()
{
    int x=0, f=1;char ch = getchar();
    while (ch < '0' || ch > '9') { if (ch == '-') f=-1; ch = getchar(); }
    while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
    return x * f;
}
int n, m, r[N];
struct complex {
    double x, y;
    complex (double xx = 0, double yy = 0) {
        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); }
complex operator / (complex a,double b) { return complex(a.x / b, a.y / b); }
void fft(int n, complex *a, int opt) {
    for (int i = 0; i < n; ++i)
        if (i < r[i])
            swap(a[i], a[r[i]]);
    for (int k = 1; k < n; k <<= 1)
    {
        complex wn = complex(cos(pi / k), opt * sin(pi / k));
        for (int i = 0; i < n; i += (k<<1))
        {
            complex w = complex(1, 0);
            for (int j = 0; j < k; ++j, w = w * wn)
            {
                complex x = a[i + j], y = w * a[i + j + k];
                a[i + j]= x + y,a[i + j + k]= x - y;
            }
        }
    }
    if (opt == -1) for (int i = 0; i < n; ++i) a[i] = a[i] / n;
}
double R[N], L[N];
long long anss;
int mx, t[M], blo;
main() {
//  freopen("input.txt","r",stdin);
    n = read();
    for (int i = 1; i <= n; ++i)
        t[i] = read(), mx = max(t[i], mx);
    blo = min(n, (int)sqrt(n) * 6);
//  blo = (int)sqrt(n);
    for (int i = 1; i <= n; ++i) R[t[i]]++;
    for (int i = 1; i <= n; i += blo) {
        int l = i, r = min(n, i + blo - 1);
        for (int j = l ; j <= r; ++j) R[t[j]]--;
        for (int j = l ; j <= r; ++j) {
            for (int k = j + 1; k <= r; ++k) {
                int temp = t[k] * 2 - t[j];
                if (temp >= 0) anss += (long long)R[temp];
                temp = t[j] * 2 - t[k];
                if (temp >= 0) anss += (long long)L[temp];
            }
            L[t[j]]++;
        }
    }
    int l = 0, fn = 1;
    while (fn <= (mx << 1)) fn <<= 1, ++l;
    for (int i = 0; i <= fn; ++i)
        r[i] = (r[i >> 1] >> 1) | ((i & 1) << (l - 1));
    for (int i = 1; i <= n; i += blo) {
        for (int j = 0; j < fn; ++j) a[j] = b[j] = complex(0,0);
        int l = i, r = min(n, i + blo - 1);
        for (int j = 1; j < l; ++j) a[t[j]].x += 1.0;
        for (int j = r + 1; j <= n; ++j) b[t[j]].x += 1.0;
        fft(fn, a, 1);
        fft(fn, b, 1);
        for (int i = 0; i <= fn; ++i)
            a[i] = a[i] * b[i];
        fft(fn, a, -1);
        for (int j = l; j <= r; ++j) anss += (long long)(a[t[j] * 2].x + 0.1);
//      for (int j = l; j <= r; ++j) printf("%d ", (long long)(ans[t[j] * 2] + 0.5));puts("");
//      printf("%I64d\n", anss);
    }
    printf("%lld\n", anss);
}