bzoj4836 [Lydsy1704月賽]二元運算(分治FFT)

題面在這裏

做法

分治+FFT優化。
按照值域分治即可。

代碼

=> 提交了整整一頁,一直在查TLE和測速 =.=
=> 先是一個奇怪卡精(?),複數類裏long double改成double就能過,否則會T。不清楚爲什麼(
=> 其次發現自己的FFT實在跑得太慢了。。。好像是我寫FFT的姿勢不對,於是稍微改動了一下。似乎變快了1000+ms..

#include<bits/stdc++.h>
#define rep(i,x,y) for (int i=(x); i<=(y); i++)
#define ll long long
#define ld long double
#define inf 1000000000
#define mset(x,y) memset((x),(y),sizeof(x))
using namespace std;
const ld pi=acos(-1);
ll read(){
    char ch=getchar(); ll x=0; int op=1;
    for (; !isdigit(ch); ch=getchar()) if (ch=='-') op=-1;
    for (; isdigit(ch); ch=getchar()) x=(x<<1)+(x<<3)+ch-'0';
    return x*op;
}
#define N 131072
int n,A[N],B[N],r[N]; ll ans[N];
struct comp{
    double a,b; comp(){} comp(double a_,double b_){ a=a_,b=b_; }
    comp operator + (const comp &t){ return comp(a+t.a,b+t.b); }
    comp operator - (const comp &t){ return comp(a-t.a,b-t.b); }
    comp operator * (const comp &t){ return comp(a*t.a-b*t.b,a*t.b+b*t.a); }
}a[N],b[N],w[N];
void pre(int n){
    w[n]=comp(1,0);
    rep (i,0,n-1){
        w[i]=comp(cos(2*i*pi/n),sin(2*i*pi/n));
        r[i]=(r[i>>1]>>1)|((i&1)*(n>>1));
        a[i]=b[i]=comp(0,0);
    }
}
void fft(comp a[],int All,int fl){
    rep (i,0,All-1) if (i<r[i]) swap(a[i],a[r[i]]);
    int n=2,m=1,x=All>>1;
    for (; n<=All; m=n,n<<=1,x>>=1)
        for (int i=0; i<All; i+=n)
            for (int k=0; k<m; k++){
                comp t=(fl?w[All-x*k]:w[x*k])*a[i+m+k];
                a[i+m+k]=a[i+k]-t;
                a[i+k]=a[i+k]+t;
            }
}
void work(int l,int r){
    if (l==r){ ans[0]+=(ll)A[l]*B[l]; return; }
    int mid=l+r>>1;
    int n1=mid-l,m1=r-mid-1;
    n=1; for (; n<=n1+m1; n<<=1); pre(n);
    rep (i,l,mid) a[i-l]=comp(A[i],0);
    rep (i,mid+1,r) b[i-mid-1]=comp(B[i],0);
    fft(a,n,0); fft(b,n,0);
    rep (i,0,n-1) a[i]=a[i]*b[i];
    fft(a,n,1);
    rep (i,0,r-l-1) ans[i+l+mid+1]+=(ll)(a[i].a/n+0.5);
    rep (i,0,n-1) a[i]=b[i]=comp(0,0);
    rep (i,mid+1,r) a[i-mid-1]=comp(A[i],0);
    rep (i,l,mid) b[mid-i]=comp(B[i],0);
    fft(a,n,0); fft(b,n,0);
    rep (i,0,n-1) a[i]=a[i]*b[i];
    fft(a,n,1);
    rep (i,0,r-l-1) ans[i+1]+=(ll)(a[i].a/n+0.5);
    work(l,mid); work(mid+1,r);
}
void solve(){
    int n=read(),m=read(),q=read();
    mset(A,0); mset(B,0); mset(ans,0);
    rep (i,1,n) A[read()]++;
    rep (i,1,m) B[read()]++;
    work(0,50000);
    while (q--) printf("%lld\n",ans[read()]);
}
int main(){
    int T=read(); while (T--) solve();
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章