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\n",1.0*ans/t);
}
}

浙公网安备 33010602011771号