题目传送门
分析:
FFT一手统计两根棍子相加的方案
然后一个值2S可能会被同一根S自己乘自己得到
然后要减去
其次,A+B和B+A会被算成两种方案,所以还要除以2
然后不太好算合法的方案数,但是非法的很好算
直接减去小于S的所有方案数乘以长度为S的棍子数就好了。。
疯狂卡常2333
#include<cstdio> #include<cmath> #include<cstring> #include<algorithm> #define maxn 500005 using namespace std; inline int getint() { int num=0,flag=1;char c; while((c=getchar())<‘0‘||c>‘9‘)if(c==‘-‘)flag=-1; while(c>=‘0‘&&c<=‘9‘)num=num*10+c-48,c=getchar(); return num*flag; } struct cp{ double a,b; cp(){} cp(double x,double y){a=x,b=y;} friend cp operator +(cp x,cp y) {return cp(x.a+y.a,x.b+y.b);} friend cp operator -(cp x,cp y) {return cp(x.a-y.a,x.b-y.b);} friend cp operator *(cp x,cp y) {return cp(x.a*y.a-x.b*y.b,x.a*y.b+x.b*y.a);} }; const double pi=acos(-1.0); int k=1,bit; cp a[maxn],b[maxn]; int rev[maxn]; long long num1[maxn],num2[maxn]; inline void fft(cp *a,int inv) { for(int i=0;i<k;i++)if(i<rev[i])swap(a[i],a[rev[i]]); for(int mid=1;mid<k;mid<<=1) { cp tmp(cos(pi/mid),inv*sin(pi/mid)); for(int i=0;i<k;i+=mid*2) { cp ret(1,0); for(int j=0;j<mid;j++,ret=ret*tmp) { cp x=a[i+j],y=ret*a[i+j+mid]; a[i+j]=x+y,a[i+j+mid]=x-y; } } } } int main() { int T=getint(); while(T--) { memset(a,0,sizeof a); int mx=0; long long n=getint();k=1,bit=0; for(int i=0;i<n;i++) { int x=getint();mx=max(mx,x); a[x].a++; } while(k<(mx+1)*2-1)k<<=1; while((1<<bit)<k)bit++; for(int i=0;i<k;i++)rev[i]=(rev[i>>1]>>1)|((i&1)<<(bit-1)); for(int i=0;i<k;i++)b[i]=a[i]; fft(a,1); for(int i=0;i<k;i++)a[i]=a[i]*a[i]; fft(a,-1); for(int i=0;i<k;i++) { num1[i]=(long long)(b[i].a+0.5), num2[i]=(long long)(a[i].a/k+0.5); if(!(i&1))num2[i]-=num1[i>>1]; num2[i]>>=1; } long long ans=(1ll*n*(n-1)*(n-2))/6; for(int i=1;i<=mx;i++)num2[i]+=num2[i-1],ans-=num2[i]*num1[i]; printf("%.7lf\n",1.0*ans*6/(n*(n-1)*(n-2))); } }
原文:https://www.cnblogs.com/Darknesses/p/12064468.html