码迷,mamicode.com
首页 > 其他好文 > 详细

HDU-4609(FFT/NTT)

时间:2019-12-24 18:36:43      阅读:104      评论:0      收藏:0      [点我收藏+]

标签:using   math   ret   fine   temp   getchar   swa   前缀和   ace   

HDU-4609(FFT/NTT)

题意: 给出n个木棒,现从中不重复地选出3根来,求能拼出三角形的概率。

计算合法概率容易出现重复,所以建议计算不合法方案数

枚举选出的最大边是哪条,然后考虑剩下两条边之和小于等于它

两条边之和为\(x\)的方案数可以\(FFT/NTT\)得到,是一个简单的构造

\(f(x)=\sum x^{length_i}\),求出\(f(x)^2\),就能得到和的方案数,但是会重复,包括自己和自己算,一对算两次

处理一下前缀和即可

#include<bits/stdc++.h>
using namespace std;

#define reg register
typedef long long ll;
#define rep(i,a,b) for(reg int i=a,i##end=b;i<=i##end;++i)
#define drep(i,a,b) for(reg int i=a,i##end=b;i>=i##end;--i)

template <class T> inline void cmin(T &a,T b){ ((a>b)&&(a=b)); } 
template <class T> inline void cmax(T &a,T b){ ((a<b)&&(a=b)); } 

char IO;
int rd(){
    int s=0,f=0;
    while(!isdigit(IO=getchar())) if(IO=='-') f=1;
    do s=(s<<1)+(s<<3)+(IO^'0');
    while(isdigit(IO=getchar()));
    return f?-s:s;
}

const double PI=acos(-1);
const int N=262150,P=998244353;
const int g=3;

int n,m;
int b[100010];
int rev[N];
typedef complex <double> Cp;
Cp d[N];
ll a[N];

void FFT(int n,Cp *a,int f){
    rep(i,0,n-1) if(rev[i]>i) swap(a[i],a[rev[i]]);
    for(reg int i=1;i<n;i<<=1) {
        Cp w(cos(PI/i),f*sin(PI/i));
        for(reg int l=0;l<n;l+=i*2) {
            Cp e(1,0);
            for(reg int j=l;j<l+i;j++,e=e*w) {
                Cp t=a[j+i]*e;
                a[j+i]=a[j]-t;
                a[j]=a[j]+t;
            }
        }
    }
}

int main(){
    rep(kase,1,rd()) {
        n=rd();
        int ma=0;
        rep(i,1,n) b[i]=rd(),d[b[i]]+=Cp(1,0),ma=max(ma,b[i]);
        int R=1,c=0;
        while(R<=ma*2) R<<=1,c++;
        rep(i,1,R) rev[i]=(rev[i>>1]>>1)|((i&1)<<(c-1));
        FFT(R,d,1);
        rep(i,0,R-1) d[i]=d[i]*d[i];
        FFT(R,d,-1);
        rep(i,0,R-1) a[i]=(ll)(d[i].real()/R+0.5);
        rep(i,1,n) a[b[i]*2]--;
        rep(i,1,R) a[i]/=2;    //处理重复情况
        rep(i,1,R) a[i]+=a[i-1];
        ll ans=0,sum=0;
        rep(i,1,n) {
            ans+=a[b[i]]; // 计算不合法方案数
            sum+=1ll*(i-1)*(i-2)/2;
        }
        rep(i,0,R+3) a[i]=0,d[i]=Cp(0,0);
        rep(i,0,ma+3) b[i]=0;
        ans=sum-ans;
        printf("%.7lf\n",1.0*ans/sum);
    }
}

HDU-4609(FFT/NTT)

标签:using   math   ret   fine   temp   getchar   swa   前缀和   ace   

原文地址:https://www.cnblogs.com/chasedeath/p/12092699.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!