0w1

IOICJ 102 No Title ( FFT )

Problem Description:
Given N integers A[ 0, N ), you want to know how many ordered tuples ( i, j, k ) satisfy:
1 ≤ i, j, k ≤ N and A[ i ] + A[ j ] = A[ k ]

Constraints:
1≤T≤10
3≤n≤1e5
−50000≤a1,a2,…,an≤50000

Sample Input:
3
3
1 2 3
4
2 2 2 2
4
-10 10 0 10

Sample Output:
3
0
15

Solution:
Let cnt[ i ] = count of appearance of value i in array A:
We could think of it as a polynomial function:
Sigma{ cnt[ i ] * x ^ i }, and we know that
cnt2 = Sigma{ cnt[ i ] * x ^ i } * Sigma{ cnt[ i ] * x ^ i }, would imply:
cnt2[ i ] = Sigma{ cnt[ j ] * cnt[ i - j ] * x ^ i }, which is exactly what we want.
However, we must map the original range [ -50000, 50000 ] to [ 0, 100000 ], then apply FFT. Note that precision handling is required.

Note:
NTT seems to be too slow to pass ...?

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef vector< int > vi;

int T;

const int MAXN = 262144 * 2;

typedef long double ld;
typedef complex< ld > cplx;
const ld PI = acos( -1.0 );
const cplx I( 0, 1 );
cplx omega[ MAXN + 1 ];
void pre_fft(){
  for( int i = 0; i <= MAXN; ++i )
    omega[ i ] = exp( i * 2 * PI / MAXN * I );
}

void fft( int n, cplx a[], bool inv = false ){
  int basic = MAXN / n;
  int theta = basic;
  for( int m = n; m >= 2; m >>= 1 ){
    int mh = m >> 1;
    for( int i = 0; i < mh; ++i ){
      cplx w = omega[ inv ? MAXN - ( i * theta % MAXN ) : i * theta % MAXN ];
      for( int j = i; j < n; j += m ){
        int k = j + mh;
        cplx x = a[ j ] - a[ k ];
        a[ j ] += a[ k ];
        a[ k ] = w * x;
      }
    }
    theta = ( theta * 2 ) % MAXN;
  }
  int i = 0;
  for( int j = 1; j < n - 1; ++j ){
    for( int k = n >> 1; k > ( i ^= k ); k >>= 1 );
    if( j < i ) swap( a[ i ], a[ j ] );
  }
  if( inv )
    for( i = 0; i < n; ++i )
      a[ i ] /= n;
}

int N;
int A[ MAXN + 1 ];

cplx cnt[ MAXN + 1 ];
cplx cnt1[ MAXN + 1 ];
cplx cnt2[ MAXN + 1 ];
cplx cnt12[ MAXN + 1 ];

void init(){
  cin >> N;
  for( int i = 0; i < N; ++i ){
    cin >> A[ i ];
    A[ i ] += 50000; // [ -50000, 50000 ] -> [ 0, 100000 ]
  }
  for( int i = 0; i <= MAXN; ++i ){
    cnt[ i ] = cplx( 0, 0 );
    cnt1[ i ] = cplx( 0, 0 );
    cnt2[ i ] = cplx( 0, 0 );
    cnt12[ i ] = cplx( 0, 0 );
  }
  for( int i = 0; i < N; ++i ){
    cnt[ A[ i ] ] += cplx( 1, 0 );
    cnt1[ A[ i ] ] += cplx( 1, 0 );
    cnt2[ A[ i ] ] += cplx( 1, 0 );
  }
  fft( MAXN / 2, cnt1 ); // convert to points
  fft( MAXN / 2, cnt2 );
  for( int i = 0; i < MAXN / 2; ++i ){ // point-wise product
    cnt12[ i ] = cnt1[ i ] * cnt2[ i ];
  }
  fft( MAXN / 2, cnt12, 1 ); // reverse point-wise product to coefficient
}

void solve(){
  ll ans = 0;
  for( int i = 0; i < MAXN / 2; ++i ){
    if( i - 50000 < 0 ) continue;
    ans += real( cnt12[ i ] ) * real( cnt[ i - 50000 ] ) + 1e-9;
  }
  cout << ans << endl;
}

signed main(){
  pre_fft();
  ios::sync_with_stdio( 0 );
  cin >> T;
  for( int ti = 0; ti < T; ++ti ){
    init();
    solve();
  }
  return 0;
}