CodeChef - COUNTARI FTT+分块

Arithmetic Progressions

Given N integers A1, A2, …. AN, Dexter wants to know how many ways he can choose three numbers such that they are three consecutive terms of an arithmetic progression.

Meaning that, how many triplets (i, j, k) are there such that 1 ≤ i < j < k ≤ Nand Aj - Ai = Ak - Aj.

So the triplets (2, 5, 8), (10, 8, 6), (3, 3, 3) are valid as they are three consecutive terms of an arithmetic
progression. But the triplets (2, 5, 7), (10, 6, 8) are not.

Input

First line of the input contains an integer N (3 ≤ N ≤ 100000). Then the following line contains N space separated integers A1, A2, …, AN and they have values between 1 and 30000 (inclusive).

Output

Output the number of ways to choose a triplet such that they are three consecutive terms of an arithmetic progression.

Example

Input:
10
3 5 3 6 3 4 10 4 5 2

Output:
9

Explanation

The followings are all 9 ways to choose a triplet

1 : (i, j, k) = (1, 3, 5), (Ai, Aj, Ak) = (3, 3, 3)
2 : (i, j, k) = (1, 6, 9), (Ai, Aj, Ak) = (3, 4, 5)
3 : (i, j, k) = (1, 8, 9), (Ai, Aj, Ak) = (3, 4, 5)
4 : (i, j, k) = (3, 6, 9), (Ai, Aj, Ak) = (3, 4, 5)
5 : (i, j, k) = (3, 8, 9), (Ai, Aj, Ak) = (3, 4, 5)
6 : (i, j, k) = (4, 6, 10), (Ai, Aj, Ak) = (6, 4, 2)
7 : (i, j, k) = (4, 8, 10), (Ai, Aj, Ak) = (6, 4, 2)
8 : (i, j, k) = (5, 6, 9), (Ai, Aj, Ak) = (3, 4, 5)
9 : (i, j, k) = (5, 8, 9), (Ai, Aj, Ak) = (3, 4, 5)

题解:

    考虑分块,分成block块

    假设三个点都在同一块,那么我们就在一块内暴力,复杂度block * ( n/block)  * (n/block)

    假设其中两个点在同一块,那么枚举其中一块的两个点算答案,block * n/block * n/block

  ·  假设三个点都不在同一块,枚举中间点属于的那一块 剩下左边和右边进行 FFT, 复杂度block * (n*logn)

    

#include<bits/stdc++.h>
using namespace std;
#pragma comment(linker, "/STACK:102400000,102400000")
#define ls i<<1
#define rs ls | 1
#define mid ((ll+rr)>>1)
#define pii pair<int,int>
#define MP make_pair
typedef long long LL;
typedef unsigned long long ULL;
const long long INF = 1e18+1LL;
const double pi = acos(-1.0);
const int N = 3e5+20, M = 1e6+10, mod = 1e9+7,inf = 2e9;

struct Complex {
    double r , i ;
    Complex () {}
    Complex ( double r , double i ) : r ( r ) , i ( i ) {}
    Complex operator + ( const Complex& t ) const {
        return Complex ( r + t.r , i + t.i ) ;
    }
    Complex operator - ( const Complex& t ) const {
        return Complex ( r - t.r , i - t.i ) ;
    }
    Complex operator * ( const Complex& t ) const {
        return Complex ( r * t.r - i * t.i , r * t.i + i * t.r ) ;
    }
} ;

void FFT ( Complex y[] , int n , int rev ) {
    for ( int i = 1 , j , t , k ; i < n ; ++ i ) {
        for ( j = 0 , t = i , k = n >> 1 ; k ; k >>= 1 , t >>= 1 ) j = j << 1 | t & 1 ;
        if ( i < j ) swap ( y[i] , y[j] ) ;
    }
    for ( int s = 2 , ds = 1 ; s <= n ; ds = s , s <<= 1 ) {
        Complex wn = Complex ( cos ( rev * 2 * pi / s ) , sin ( rev * 2 * pi / s ) ) , w ( 1 , 0 ) , t ;
        for ( int k = 0 ; k < ds ; ++ k , w = w * wn ) {
            for ( int i = k ; i < n ; i += s ) {
                y[i + ds] = y[i] - ( t = w * y[i + ds] ) ;
                y[i] = y[i] + t ;
            }
        }
    }
    if ( rev == -1 ) for ( int i = 0 ; i < n ; ++ i ) y[i].r /= n ;
}
Complex s[N],t[N];

LL cnt[502][30005];
int a[N];
int n,block,pos[N];
LL vis[N];
int main() {
    while(scanf("%d",&n)!=EOF) {
        block = 1500;
        for(int i = 1; i <= n; ++i)
            pos[i] = (i-1)/block + 1;
        int mx = -1;
        for(int i = 0; i <= pos[n]; ++i)
        for(int j = 1; j <= 30000; ++j) cnt[i][j] = 0;
        for(int i = 1; i <= n; ++i) {
            scanf("%d",&a[i]);
            mx = max(mx,a[i]);
            cnt[pos[i]][a[i]]++;
        }

        for(int i = 1; i <= mx; ++i) {
            for(int j = 1; j <= pos[n]; ++j) {
                cnt[j][i] += cnt[j-1][i];
            }
        }
        int len = 1;
        while(len <= 2*mx) len<<=1;
        LL ans = 0;
        for(int k = 1; k <= pos[n]; ++k) {
            for(int i = (k-1)*block + 1; i <= min(k*block,n); ++i) {
                for(int j = i + 1; j <= min(k*block,n); ++j) {
                    if(2*a[i] - a[j] >= 1 && 2*a[i] - a[j] <= mx)
                        ans += cnt[k-1][2*a[i] - a[j]] + vis[2*a[i]-a[j]];
                    if(2*a[j] - a[i] >= 1 &&  2*a[j] - a[i] <= mx)
                        ans += cnt[pos[n]][2*a[j] - a[i]] - cnt[k][2*a[j] - a[i]];
                }
                vis[a[i]] += 1;
            }
            for(int i = (k-1)*block + 1; i <= min(k*block,n); ++i) {
                vis[a[i]] = 0;
            }

            for(int j = 0; j <= mx; ++j)
                s[j] = Complex(cnt[k-1][j],0);
            for(int j = mx+1; j < len; ++j) s[j] = Complex(0,0);

            for(int j = 0; j <= mx; ++j)
                t[j] = Complex(cnt[pos[n]][j] - cnt[k][j] , 0);
            for(int j = mx+1; j < len; ++j) t[j] = Complex(0,0);

            FFT(s,len,1);FFT(t,len,1);
            for(int j = 0; j < len; ++j) s[j] = s[j] * t[j];
            FFT(s,len,-1);

            for(int j = 1; j <= mx; ++j) {
                LL tmp = (LL)(s[2*j].r + 0.5);
                ans += tmp*(cnt[k][j] - cnt[k-1][j]);
            }
        }
        printf("%lld\n",ans);

    }
    return 0;
}

  

时间: 2024-09-30 16:25:12

CodeChef - COUNTARI FTT+分块的相关文章

CodeChef COUNTARI Arithmetic Progressions(分块 + FFT)

题目 Source http://vjudge.net/problem/142058 Description Given N integers A1, A2, …. AN, Dexter wants to know how many ways he can choose three numbers such that they are three consecutive terms of an arithmetic progression. Meaning that, how many trip

CodeChef FNCS (分块+树状数组)

题目:https://www.codechef.com/problems/FNCS 题解: 我们知道要求区间和的时候,我们用前缀和去优化.这里也是一样,我们要求第 l 个函数到第 r 个函数 [l, r] 的函数和,那么我们可以用 sum[r] - sum[l-1] 来求得. 由于这个数据量有点大,所以我们将函数分块. 例如样例: 1 3 有5个函数,那么我们分成3块.{ [1 3] , [2 5] }, { [4 5], [3 5] }, { [1 2] }.每一块对应都有一个sum ,这时如

CodeChef - COUNTARI Arithmetic Progressions (FFT)

题意:求一个序列中,有多少三元组$(i,j,k)i<j<k $ 满足\(A_i + A_k = 2*A_i\) 构成等差数列. https://www.cnblogs.com/xiuwenli/p/9719425.html 在该题的基础上加了i<j<k的限制.不能单纯地FFT枚举结果. 考虑分块搭配FFT结果问题. 将原序列分成若干块,设每个块的大小为\(B\).则构成等差数列的三元组有三种构成情况. 1)三个数都在一个块内.这种情况对每个块独立处理.二重循环枚举\(A_i .A_

CC countari &amp; 分块+FFT

题意: 求一个序列中顺序的长度为3的等差数列. SOL: 对于这种计数问题都是用个数的卷积来进行统计.然而对于这个题有顺序的限制,不好直接统计,于是竟然可以分块?惊为天人... 考虑分块以后的序列: 一个块内直接枚举统计三个或两个在块内的. 只有一个在当前块我们假设它是中间那个,对左右其它块做卷积. 但是还是感觉复杂度有点玄学啊... 我比较傻逼...一开始块内统计根本没有想清楚...最后做卷积硬生生把复杂度变成了 $\sqrt{N}*N*log(N)$... 改了一个晚上终于没忍住看标程...

CodeChef - QCHEF 分块

题目链接:http://vjudge.net/problem/174774/origin 题意:给定一个长度为n的序列a[],序列的值不大于m,现在有k个询问,每个询问给定(l,r).让你求出max{|x − y| : Li ≤ x, y ≤ Ri and Ax = Ay}.即区间[L,R]中值相同时,位置差的最大值 思路:分块,因为不带修改,所以我们就可以做预处理.求出last,first,Ans. last[i][j]:值i在第j块最后出现的位置.first[i][j]:值i在第j块最早出现

【xsy2111】 【CODECHEF】Chef and Churus 分块+树状数组

题目大意:给你一个长度为$n$的数列$a_i$,定义$f_i=\sum_{j=l_i}^{r_i} num_j$. 有$m$个操作: 操作1:询问一个区间$l,r$请你求出$\sum_{i=l}^{r} f_i$. 操作2:将$a_x$变成$y$. 此题貌似正常做都不是很好做,考虑用一些奇奇怪怪的做法(比如说分块) 考虑到此题数列在不断地变化,我们考虑用树状数组来维护序列$a$,查询$f_i$的值可以在$O(log n)$的时间内完成. 如果这么做,单次询问的复杂度是$O(n log n)$的,

[codechef FNCS]分块处理+树状数组

题目链接:https://vjudge.net/problem/CodeChef-FNCS 在一个地方卡了一晚上,就是我本来以为用根号n分组,就会分成根号n个.事实上并不是....因为用的是根号n下取整分组,得到的组数要用n/floor(sqrt(n))具体计算. 另外还有各种奇怪的bug--包括unsigned long long什么的--orz #include<bits/stdc++.h> using namespace std; typedef unsigned long long u

CodeChef Arithmetic Progressions

https://www.codechef.com/status/COUNTARI 题意: 给出n个数,求满足i<j<k且a[j]-a[i]==a[j]-a[k] 的三元组(i,j,k)的个数 n^2 做法: 枚举j和k,当j右移时,令sum[num[右移之前j的值]]++ 每次统计sum[num[j]*2-num[k]]即可 如果没有i<j<k,直接上FFT 但是有了这个限制,可以枚举j,再FFT,复杂度为n*n*log(30000) 考虑一次FFT只算1个j有点儿浪费 能不能算好

Maximum number, GCD condition (codechef March Challenge 2014)

题目 : http://acm.bnu.edu.cn/v3/problem_show.php?pid=40489 最近做到的一道蛮有意思的题目(codechef现在的题目确实很赞了) 题意 :中文题面 (cc的一大好处就是有中文翻译,嘿嘿) 区间Max = max{a_i|gcd(a_i, g) > 1 && x <= i <= y} 做法 : 一开始我是用分块做的,复杂的O(m * sqrt(n) * C) C 是所含不同素数的个数, C大概最大只有6或7吧 然后裸裸的