分块大法好。
块内暴力,块外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 ",ans); }