# HDU4609 3-idiots

FFT不要忘记最后除以n

### 参考程序

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;

const long long MaxAlpha = 300010;
const long long FullAlpha = 100000;
const long long Maxn = 100010;
const double Pi = 3.14159265358979323846264;
void Work();
void Init();
int main() {
int TestCases;
scanf( "%d", &TestCases );
for( ; TestCases--; ) Work();
return 0;
}

long long n, m, A[ Maxn ];
long long Sum[ MaxAlpha ];
long long UpTo;

struct MyComplex {
double Real, Imagine;
MyComplex() {}
MyComplex( double _Real, double _Imagine ) : Real( _Real ), Imagine( _Imagine ) {}
inline MyComplex operator + ( const MyComplex Other ) const {
return ( MyComplex ) { Real + Other.Real, Imagine + Other.Imagine };
}
inline MyComplex operator - ( const MyComplex Other ) const {
return ( MyComplex ) { Real - Other.Real, Imagine - Other.Imagine };
}
inline MyComplex operator * ( const MyComplex Other ) const {
return ( MyComplex ) { Real * Other.Real - Imagine * Other.Imagine, Real * Other.Imagine + Imagine * Other.Real };
}
};
MyComplex FFT_A[ MaxAlpha ], FFT_B[ MaxAlpha ], Omega[ MaxAlpha ];
long long FFT_Index[ MaxAlpha ];
void FFT( MyComplex *A, long long Len ) {
for( long long i = 0; i < Len; ++i )
if( i < FFT_Index[ i ] )
swap( A[ i ], A[ FFT_Index[ i ] ] );
for( long long Half = 1; Half < Len; Half <<= 1 )
for( long long i = 0; i < Len; i += Half << 1 )
for( long long j = 0; j < Half; ++j ) {
MyComplex Temp = Omega[ ( Len / Half / 2 ) * j ] * A[ i + j + Half ];
MyComplex T = A[ i + j ];
A[ i + j ] = Temp + T;
A[ i + j + Half ] = T - Temp;
}
return;
}
long long FFT_MAIN() {
FFT( FFT_A, UpTo ); FFT( FFT_B, UpTo );
for( long long i = 0; i < UpTo; ++i ) FFT_A[ i ] = FFT_A[ i ] * FFT_B[ i ];
for( long long i = 0; i < UpTo; ++i ) Omega[ i ].Imagine = -Omega[ i ].Imagine;
FFT( FFT_A, UpTo );
for( long long i = 0; i < UpTo; ++i ) FFT_A[ i ].Real = floor( FFT_A[ i ].Real / UpTo + 0.5 );
return UpTo;
}
void Init( long long Need) {   //FFT初始化
memset( FFT_Index, 0, sizeof( FFT_Index ) );
memset( Omega, 0, sizeof( Omega ) );
long long Len = 2 * Need - 1;
for( UpTo = 1; UpTo <= Len; UpTo <<= 1 );
for( long long i = 0; i < UpTo; ++i )
FFT_Index[ i ] = ( FFT_Index[ i >> 1 ] >> 1 ) | ( ( i & 1 ) * ( UpTo >> 1 ) );
for( long long i = 0; i < UpTo; ++i )
Omega[ i ] = ( MyComplex ) { cos( 2.0 * Pi * i / UpTo ), sin( 2.0 * Pi * i / UpTo ) };
return;
}
void Work() {
scanf( "%lld", &n );
for( long long i = 1; i <= n; ++i ) scanf( "%lld", &A[ i ] );
m = 0; for( long long i = 1; i <= n; ++i ) m = max( m, A[ i ] );
Init( m + 1 );

memset( FFT_A, 0, sizeof( FFT_A ) );
for( long long i = 1; i <= n; ++i ) FFT_A[ A[ i ] ].Real += 1;
memcpy( FFT_B, FFT_A, sizeof( FFT_B ) );

FFT_MAIN();   //FFT求两条边的长度和的所有情况

for( long long i = 1; i <= n; ++i ) FFT_A[ A[ i ] + A[ i ] ].Real -= 1.0;//两条相同的边是不被允许的
for( long long i = 0; i < UpTo; ++i ) FFT_A[ i ].Real /= 2.0;//不同顺序选两条边认为是相同情况

memset( Sum, 0, sizeof( Sum ) );
for( long long i = 1; i < UpTo; ++i ) Sum[ i ] = Sum[ i - 1 ] + FFT_A[ i ].Real;//前缀和预处理
long long Ans = 0;
sort( A + 1, A + n + 1 );
for( int i = 1; i <= n; ++i ) {
long long Temp = Sum[ UpTo - 1 ] - Sum[ A[ i ] ];//和大于当前枚举边的所有情况
Temp -= n - 1;//枚举的这条边不能再被选
Temp -= ( n - i ) * ( i - 1 );//减去其中一条边大于当前边的情况
Temp -= ( n - i - 1 ) * ( n - i ) / 2;//减去两条边都大于当前边的情况
Ans += Temp;
}
long long Total = 1LL * n *( n - 1 ) * ( n - 2 ) / 6;
printf( "%.7lf\n", 1.0 * Ans / Total );
return;
}
posted @ 2019-09-02 16:43 chy_2003 阅读(...) 评论(...) 编辑 收藏