BZOJ 3509 [CodeChef] COUNTARI ——分块 FFT

分块大法好。

块内暴力,块外FFT。

弃疗了,抄SX队长$silvernebula$的代码

#include <map>
#include <cmath>
#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define F(i,j,k) for (int i=j;i<=k;++i)
#define D(i,j,k) for (int i=j;i>=k;--i)
#define ll long long
#define mp make_pair
#define maxn 200005
 
struct Complex{
    double x,y;
    Complex (){}
    Complex (double _x,double _y){x=_x;y=_y;}
    Complex operator + (Complex a){return Complex(x+a.x,y+a.y);}
    Complex operator - (Complex a){return Complex(x-a.x,y-a.y);}
    Complex operator * (Complex a){return Complex(x*a.x-y*a.y,x*a.y+y*a.x);}
}A[maxn],B[maxn],C[maxn];
 
int rev[maxn],T,len,w[maxn],cnt=0,L[maxn],R[maxn],N,n,Rc[maxn],Lc[maxn];
ll ans;
const double pi=acos(-1.0);
 
void FFT(Complex * x,int n,int flag)
{
    F(i,0,n-1) if (rev[i]>i) swap(x[rev[i]],x[i]);
    for (int m=2;m<=n;m<<=1)
    {
        Complex wn=Complex(cos(2*pi/m),flag*sin(2*pi/m));
        for (int i=0;i<n;i+=m)
        {
            Complex w=Complex(1.0,0);
            for (int j=0;j<(m>>1);++j)
            {
                Complex u=x[i+j],v=x[i+j+(m>>1)]*w;
                x[i+j]=u+v;x[i+j+(m>>1)]=u-v;w=w*wn;
            }
        }
    }
    if (flag==-1) F(i,0,n-1) x[i].x/=n;
}
 
void solve(int id)
{
    int x;
    F(i,L[id],R[id])
    {
        --Rc[w[i]];
        F(j,L[id],i-1){x=w[i]*2-w[j];if(x>=0)ans+=Rc[x];}
        F(j,i+1,R[id]){x=w[i]*2-w[j];if(x>=0)ans+=Lc[x];}
    }
    if (id>1&&id<cnt)
    {
        memset(A,0,sizeof A);
        memset(B,0,sizeof B);
        F(i,1,L[id]-1) A[w[i]].x+=1;
        F(i,R[id]+1,n) B[w[i]].x+=1;
        FFT(A,N,1);FFT(B,N,1);
        F(i,0,N-1)A[i]=A[i]*B[i];FFT(A,N,-1);
        F(i,L[id],R[id]) ans+=(ll)(A[w[i]<<1].x+0.3);
    }
    F(i,L[id],R[id]) ++Lc[w[i]];
}
 
int main()
{
    scanf("%d",&n);F(i,1,n)scanf("%d",&w[i]);T=2000;cnt=0;
    while (cnt*T<n) L[++cnt]=R[cnt-1]+1,R[cnt]=cnt*T;
    R[cnt]=min(R[cnt],n);for(N=1,len=0;N<=60000;N<<=1)len++;
    F(i,0,N-1) rev[i]=(rev[i>>1]>>1)|((i&1)<<(len-1));
    D(i,n,1) Rc[w[i]]++; F(i,1,cnt) solve(i);
    printf("%lld\n",ans);
}

  

转载于:https://www.cnblogs.com/SfailSth/p/6776451.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值