BZOJ 3513: [MUTC2013]idiots [FFT]

统计每种长度的木棒数量,先计算出两根棒子能构成的长度,想到卷积。1.拿这个序列卷积自己 2.计算重算的部分,首先是一条边自己和自己的这种情况,另一种是(i,j)和(j,i)这种形式。第一种,可以枚举读入的木棒长度,再长度为其二倍的位置-1;第二种,在第一种处理完之后,直接除2。计算出两根棒子能构成的长度后,我们枚举最长的那条边,答案一定在长度大于它的里面,但是要去掉算了自己的情况,和存在一条边大于最长边的情况。具体公式看代码。这题中间精度差了些就挂了。可以用long long就不要用double。

#include <bits/stdc++.h>
#define pi acos(-1.0)
const int maxn = 300000+5;
using namespace std;
typedef long long ll;
struct E{
    double real,imag;
    E(double real=0,double imag=0):real(real),imag(imag){}
    friend E operator +(E A,E B){
        return E(A.real+B.real,A.imag+B.imag);
    }
    friend E operator -(E A,E B){
        return E(A.real-B.real,A.imag-B.imag);
    }
    friend E operator *(E A,E B){
        return E(A.real*B.real-A.imag*B.imag,A.imag*B.real+A.real*B.imag);
    }
};
int n,m,mx,L,rev[maxn];
E f[maxn],rf[maxn],g[maxn],e1[maxn],e2[maxn];
void fft(E *a,int ty,int n){
    for(int i=0;i<n;++i)if(i<rev[i])swap(a[i],a[rev[i]]);
    for(int i=1;i<n;i<<=1){
        E wn=E(cos(pi/i),ty*sin(pi/i));
        for(int p=(i<<1),j=0;j<n;j+=p){
            E w(1,0);
            for(int k=0;k<i;++k,w=w*wn){
                E x=a[j+k],y=w*a[j+k+i];
                a[j+k]=x+y;a[j+k+i]=x-y;
            }
        }
    }
    if(ty==-1)for(int i=0;i<n;++i)a[i].real/=n;
}
E c[maxn];
int T;
ll e[maxn],F[maxn],b[maxn];
int main() {
    scanf("%d",&T);
    while(T--) {ll mx = 0;
        scanf("%lld",&n); L=0;
        memset(c,0,sizeof(c));
        memset(e,0,sizeof(e));
        memset(rev,0,sizeof(rev));
        memset(F,0,sizeof(F));
        for(int i=1;i<=n;++i) {
            scanf("%lld",&e[i]);
            ++F[e[i]];
            mx = max(mx,e[i]);
        }
        m = mx*2;for(mx=1;mx<=m;mx<<=1)++L;
        for(int i=0;i<mx;++i)rev[i]=(rev[i>>1]>>1)|((i&1)<<(L-1));
        for(int i=0;i<mx;++i)c[i]=F[i];
        fft(c,1,mx);
        for(int i=0;i<mx;++i) c[i]=c[i]*c[i];
        fft(c,-1,mx);
        for(int i=0;i<mx;++i)
            b[i] = (ll)(c[i].real+0.5);
        for(int i=1;i<=n;++i) --b[e[i]<<1];
        for(int i=0;i<mx;++i) b[i]>>=1;
        for(int i=1;i<mx;++i) b[i]+=b[i-1];
        sort(e+1,e+1+n);ll ans = 0;
        for(int i=1;i<=n;++i){
            ans = ans + (ll)(b[mx-1]-b[e[i]]);
            ans -= (ll)(n-1LL);
            ans -= (ll)(n-i)*(i-1);
            ans -= (ll)(n-i)*(n-i-1LL)/2LL;
        }
        ll t = 1LL*n*(n-1LL)*(n-2LL)/6LL;
        printf("%.7f
",1.0*ans/t);
    }
}

  

原文地址:https://www.cnblogs.com/RRRR-wys/p/8967563.html