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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值