fft+分治 ifrog1044 Quailty and Binary Operation

传送门:点击打开链接

题意:给出A数组和B数组,对于每一个A[i],B[j],如果A[i]>=B[j],则变成A[i]-B[j],否则A[i]+B[j]

思路:很显然可以看出fft。但是刚开始却很难想到怎么去把两种情况给分开。

这里有个非常神奇的思路,那就是分治,把区间分成2个部分。A[l,m],A[m+1,r],B[l,m],B[m+1,r]

计算A[l,m]和B[l,m],以及A[m+1,r]和B[m+1,r]对答案贡献时,直接递归

计算A[l,m]和B[m+1,r],以及A[m+1,r]和B[l,m]对答案的贡献时,用fft

这里fft时也非常有技巧,因为两个数组完全独立,所以最后的总长度到达当前递归时区间长度就行了。

关于fft时下标的前后转换,我们可以通过表示出之前的下标,和变换后的下标直接的等量关系,

可以定向的通过数学表达式而搞定。

这道题比较卡时间,顺手加了个输入挂

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define fuck(x) cout<<"["<= k) {
            j -= k;
            k /= 2;
        }
        if(j < k) j += k;
    }
}
void fft(complex y[], int len, int on) {
    change(y, len);
    for(int h = 2; h <= len; h <<= 1) {
        complex wn(cos(on * 2 * PI / h), sin(on * 2 * PI / h));
        for(int j = 0; j < len; j += h) {
            complex w(1, 0);
            for(int k = j; k < j + h / 2; k++) {
                complex u = y[k];
                complex t = w * y[k + h / 2];
                y[k] = u + t;
                y[k + h / 2] = u - t;
                w = w * wn;
            }
        }
    }
    if(on == -1) {
        for(int i = 0; i < len; i++) {
            y[i].r /= len;
        }
    }
}


const int MX = 2e5 + 5;
complex a[MX], b[MX];
int n, m, q;
int A[MX], B[MX];
LL ans[MX];


void solve1(int L, int R) {
    int M = (L + R) >> 1, w = R - L + 1, len;
    for(len = 1; len < w; len <<= 1);
    for(int i = 0; i < len; i++) {
        a[i] = (i + L <= M) ? complex(A[i + L], 0) : complex(0, 0);
        b[i] = (M + 1 + i <= R) ? complex(B[M + 1 + i], 0) : complex(0, 0);
    }
    fft(a, len, 1); fft(b, len, 1);
    for(int i = 0; i < len; i++) {
        a[i] = a[i] * b[i];
    }
    fft(a, len, -1);
    for(int i = 0; i < len; i++) {
        LL t = a[i].r + 0.5;
        ans[L + M + 1 + i] += t;
    }
}
void solve2(int L, int R) {
    int M = (L + R) >> 1, w = R - L + 1, len;
    for(len = 1; len < w; len <<= 1);
    for(int i = 0; i < len; i++) {
        a[i] = (M + 1 + i <= R) ? complex(A[M + 1 + i], 0) : complex(0, 0);
        b[i] = (i + L <= M) ? complex(B[M - i], 0) : complex(0, 0);
    }
    fft(a, len, 1); fft(b, len, 1);
    for(int i = 0; i < len; i++) {
        a[i] = a[i] * b[i];
    }
    fft(a, len, -1);
    for(int i = 0; i + 1 < len; i++) {
        LL t = a[i].r + 0.5;
        ans[i + 1] += t;
    }
}
void cdq(int L, int R) {
    if(L == R) {
        ans[0] += (LL)A[L] * B[L];
        return;
    }
    int M = (L + R) >> 1;
    cdq(L, M); cdq(M + 1, R);
    solve1(L, R); solve2(L, R);
}
namespace IO {
    const int MT = 2e7;
    char buf[MT]; int c, sz;
    void begin() {
        c = 0;
        sz = fread(buf, 1, MT, stdin);
    }
    inline bool read(int &t) {
        while(c < sz && buf[c] != '-' && (buf[c] < '0' || buf[c] > '9')) c++;
        if(c >= sz) return false;
        bool flag = 0; if(buf[c] == '-') flag = 1, c++;
        for(t = 0; c < sz && '0' <= buf[c] && buf[c] <= '9'; c++) t = t * 10 + buf[c] - '0';
        if(flag) t = -t;
        return true;
    }
}
int main() {
    int T; //FIN;FOUT;
    IO::begin();
    IO::read(T);
    while(T--) {
        memset(ans, 0, sizeof(ans));
        memset(A, 0, sizeof(A));
        memset(B, 0, sizeof(B));


        int Max = 0;
        IO::read(n); IO::read(m); IO::read(q);
        for(int i = 1; i <= n; i++) {
            int t; IO::read(t);
            Max = max(Max, t);
            A[t]++;
        }
        for(int i = 1; i <= m; i++) {
            int t; IO::read(t);
            Max = max(Max, t);
            B[t]++;
        }
        cdq(0, Max);
        while(q--) {
            int t; IO::read(t);
            printf("%lld\n", ans[t]);
        }
    }
    return 0;
}


你可能感兴趣的:(ACM_FFT)