1. 程式人生 > >UVA12879 Golf Bot FFT

UVA12879 Golf Bot FFT

傳送門

題意:給出一個長度為$N$的數列$a_i$,再給出$M$個目標數字$d_i$,問目標數字中有多少個等於$a_i$或$a_i+a_j$($i,j \in [1,N]$,不要求$i,j$不相等)。$1 \leq N , M , a_i , d_i \leq 2 \times 10^5$


 

首先,等於$a_i$相當於等於$a_i+0$,那麼把$0$丟進$a_i$中就變成了詢問目標數字中有多少個等於$a_i$中兩個數字之和。

考慮到$a_i$與$a_j$會對$a_i+a_j$產生貢獻,與卷積類似,故使用$FFT$解決。與生成函式類似(好像就是生成函式),將$A_{a_i}$與$B_{a_i}$$(i \in [1 , N])$設為$1$,其餘設為$0$,做$FFT$。設$FFT$結果陣列為$C$,那麼如果$C_{d_i}>0$,意味著$d_i$是能被$a_i$中某兩個元素表示的,答案++即可。

#include<bits/stdc++.h>
#define ld long double
#define eps 1e-2
//This code is written by Itst
using namespace std;

inline int read(){
    int a = 0;
    bool f = 0;
    char c = getchar();
    while(c != EOF && !isdigit(c)){
        if(c == '-')
            f = 1;
        c = getchar();
    }
    
while(c != EOF && isdigit(c)){ a = (a << 3) + (a << 1) + (c ^ '0'); c = getchar(); } return f ? -a : a; } const int MAXN = 530010; struct comp{ ld x , y; comp(ld _x = 0 , ld _y = 0){ x = _x; y = _y; } comp operator +(comp a){
return comp(x + a.x , y + a.y); } comp operator -(comp a){ return comp(x - a.x , y - a.y); } comp operator *(comp a){ return comp(x * a.x - y * a.y , x * a.y + y * a.x); } }A[MAXN] , B[MAXN]; int need , dir[MAXN]; const ld pi = acos(-1); bool cmp(ld a , ld b){ return a - eps < b && a + eps > b; } inline void FFT(comp* a , int type){ for(int i = 1 ; i < need ; ++i) if(i < dir[i]) swap(a[i] , a[dir[i]]); for(int i = 1 ; i < need ; i <<= 1){ comp wn(cos(pi / i) , type * sin(pi / i)); for(int j = 0 ; j < need ; j += i << 1){ comp w(1 , 0); for(int k = 0 ; k < i ; ++k , w = w * wn){ comp x = a[j + k] , y = a[i + j + k] * w; a[j + k] = x + y; a[i + j + k] = x - y; } } } } int main(){ #ifndef ONLINE_JUDGE freopen("12879.in" , "r" , stdin); freopen("12879.out" , "w" , stdout); #endif while(int N = read()){ memset(&A , 0 , sizeof(A)); memset(&B , 0 , sizeof(B)); int maxN = 0 , cnt = 0; for(int i = 1 ; i <= N ; ++i){ int a = read(); A[a].x = B[a].x = 1; maxN = max(maxN , a); } A[0].x = B[0].x = 1; need = 1; while(need <= maxN << 1) need <<= 1; for(int i = 1 ; i < need ; ++i) dir[i] = (dir[i >> 1] >> 1) | (i & 1 ? need >> 1 : 0); FFT(A , 1); FFT(B , 1); for(int i = 0 ; i < need ; ++i) A[i] = A[i] * B[i]; FFT(A , -1); for(int M = read() ; M ; --M) if(!cmp(0 , A[read()].x)) ++cnt; printf("%d\n" , cnt); } return 0; }