题意:给你n个木棍,让你求取三根木棍能组成三角形的概率,其实就是问你组成三角形的方法有多少种
思路:一点思路都没有,看了kuangbin聚聚的博客才理解了为什么要用FFT,以及之后的去重,写的很详细,但是这个题卡了内存,理解了以后用胡小兔爷的FFT,一直爆内存,主要是因为在求FFT的时候打复平面点,和他的倒数的那个位置,胡小兔爷是直接预处理打表的,QAQ,只好改成用的时候在进行计算的办法了
代码:
#include <bits/stdc++.h> using namespace std; const int N = 400040; const double PI=acos(-1.0); struct cp { double r,i; cp(){} cp(double _r,double _i) { r=_r;i=_i; } cp operator +(const cp &a)const { return cp(a.r+r,a.i+i); } cp operator -(const cp &a)const { return cp(r-a.r,i-a.i); } cp operator *(const cp &a)const { return cp(r*a.r-i*a.i,r*a.i+i*a.r); } cp conj() { return cp(r,-i); } }; void change(cp y[],int len) { int i,j,k; for(i = 1, j = len/2;i < len-1;i++) { if(i < j)swap(y[i],y[j]); k = len/2; while( j >= k) { j -= k; k /= 2; } if(j < k)j += k; } } void fft(cp y[],int len,int on) { change(y,len); // for(int i=2;i<=len;i++){ // printf("%d == %f ",i,y[i].r); // } // puts(""); for(int h = 2;h <= len;h <<= 1) { cp wn(cos(-on*2*PI/h),sin(-on*2*PI/h)); for(int j = 0;j < len;j += h) { cp w(1,0); for(int k = j;k < j+h/2;k++) { cp u = y[k]; cp t = w*y[k+h/2]; y[k] = u+t; y[k+h/2] = u-t; w = w*wn; } } } if(on == -1) for(int i = 0;i < len;i++) y[i].r /= len; } int a[N/4]; long long num[N],sum[N]; cp x[N]; int main() { int T,n,m; scanf("%d",&T); while(T--){ scanf("%d",&n); memset(num,0,sizeof(num)); for(int i=0;i<n;i++){ scanf("%d",&a[i]); num[a[i]]++; } sort(a,a+n); m=a[n-1]+1; int as=1; while(as<2*m)as<<=1; for(int i=0;i<m;i++){ x[i]=cp(num[i],0); } for(int i=m;i<as;i++){ x[i]=cp(0,0); } // FFT_init(); fft(x,as,1); for(int i=0;i<as;i++){ x[i]=x[i]*x[i]; } fft(x,as,-1); for(int i=0;i<as;i++){ num[i]=(long long)(x[i].r+0.5); } as=2*a[n-1]; for(int i=0;i<n;i++){ num[a[i]+a[i]]--; } for(int i=1;i<=as;i++){ num[i]/=2; } sum[0]=0; for(int i=1;i<=as;i++){ sum[i]=sum[i-1]+num[i]; } long long ans=0; for(int i=0;i<n;i++){ ans+=sum[as]-sum[a[i]]; ans-=(long long)(n-1-i)*i; ans-=(n-1); ans-=(long long)(n-1-i)*(n-i-2)/2; } long long tot=(long long)n*(n-1)*(n-2)/6; printf("%.7f ",(double)ans/tot); } } /* 2 4 1 3 3 4 4 2 3 3 4 */