BZOJ3513: [MUTC2013]idiots

Description

给定n个长度分别为a_i的木棒,问随机选择3个木棒能够拼成三角形的概率。

Input

第一行T(T<=100),表示数据组数。
接下来若干行描述T组数据,每组数据第一行是n,接下来一行有n个数表示a_i。

Output

T行,每行一个整数,四舍五入保留7位小数。

Sample Input

2
4
1 3 3 4
4
2 3 3 4

Sample Output

0.5000000
1.0000000

HINT

T<=20


N<=100000

Source

第一道FFT的题。
BZOJ上有一个条件没说:0<=a_i<=100000。
那么我们可以设f[i]为用两个木棒组成长度为i的方案数。
我们发现这个可用卷积求,于是这道题就做完了。
#include<cstdio>
#include<cctype>
#include<queue>
#include<cmath>
#include<cstring>
#include<algorithm>
#define rep(i,s,t) for(int i=s;i<=t;i++)
#define dwn(i,s,t) for(int i=s;i>=t;i--)
#define ren for(int i=first[x];i!=-1;i=next[i])
using namespace std;
inline int read() {
    int x=0,f=1;char c=getchar();
    for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
    for(;isdigit(c);c=getchar()) x=x*10+c-'0';
    return x*f;
}
const int maxn=300010;
const double PI=acos(-1.0);
typedef long long ll;
struct FFT {
    struct cox {
        double r,i;
        cox(double _r=0.0,double _i=0.0) {r=_r;i=_i;}
        cox operator + (const cox& b) const {return cox(r+b.r,i+b.i);}
        cox operator - (const cox& b) const {return cox(r-b.r,i-b.i);}
        cox operator * (const cox& b) const {return cox(r*b.r-i*b.i,r*b.i+i*b.r);}
    }f[maxn];
    int len;
    void init(int* A,int L,int Len) {
        len=L;rep(i,0,Len-1) f[i]=cox(A[Len-i-1],0);rep(i,Len,L-1) f[i]=cox(0,0);
    }
    void cal(int tp) {
        int j=len>>1;
        rep(i,1,len-2) {
            if(i<j) swap(f[i],f[j]);int k=len>>1;
            while(j>=k) j-=k,k>>=1;j+=k;
        }
        double lm=-2*tp*PI;
        for(int i=2;i<=len;i<<=1) {
            cox wn(cos(lm/i),sin(lm/i));
            for(int j=0;j<len;j+=i) {
                cox w(1,0);
                for(int k=j;k<j+(i>>1);k++) {
                    cox u=f[k],v=w*f[k+(i>>1)];
                    f[k]=u+v;f[k+(i>>1)]=u-v;w=w*wn;
                }
            }
        }
        if(tp<0) rep(i,0,len-1) f[i].r/=len;
    }
};
void mul(int* A,int* B,int L1,int L2,int& L,ll* ans) {
    L=1;while(L<L1<<1||L<L2<<1) L<<=1;
    static FFT a,b;a.init(A,L,L1);b.init(B,L,L2);
    a.cal(1);b.cal(1);rep(i,0,L-1) a.f[i]=a.f[i]*b.f[i];
    a.cal(-1);rep(i,0,L-1) ans[i]=ll(a.f[i].r+0.5);
}
int A[maxn];
ll ans[maxn],sum[maxn];
int main() {
    int T=read();
    while(T--) {
        memset(A,0,sizeof(A));
        int n=read(),v,L1=0,L;
        rep(i,1,n) A[v=read()]++,L1=max(L1,v+1);A[0]=0;
        mul(A,A,L1,L1,L,ans);
        while(L>L1+L1-1&&!ans[L-1]) L--;
        dwn(i,L-1,0) sum[L-1-i]=ans[i];
        rep(i,1,L-1) sum[i]=(sum[i]-(i&1?0:A[i>>1]))/2;
        ll res=0,tmp=0,all=0;
        dwn(i,L-1,1) tmp+=A[i],res+=tmp*sum[i];
        rep(i,1,n) all+=(ll)(n-i)*(n-i-1)/2;
        printf("%.7lf
",1.0-(double)res/all);
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/wzj-is-a-juruo/p/4695787.html