zoukankan      html  css  js  c++  java
  • HDU4609 3-idiots

    题目链接

    问题分析

    题意就是求随机取(3)条边能组成长方形的概率。其实可以看做求方案数。

    不妨将边长从小到大排序,得到(a_1,a_2,cdots,a_n)。考虑枚举三角形边长中最大的一条(a_i),那么(a_i)作为最大边时贡献就是(a_1,a_2,cdots,a_{i-1})中两项加起来大于(a_i)的方案数。然而发现这样比较难将复杂度降到(O(nlog n))

    不妨换一个角度考虑。首先求出取两条边可能的所有情况,然后再枚举第三条边。和上面一样,让枚举的第三条边是三角形中最大的边,然后去重即可。由于边长范围只有(1e5),通过母函数和FFT来求得。具体细节可以看代码。假装100组数据(O(nlog n))能过就好了

    注意使用long long

    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
    ", 1.0 * Ans / Total );
    	return;
    }
    
  • 相关阅读:
    Ubuntu18.04安装RTX2080Ti+NVIDIA驱动+CUDA
    G++ 编译多个源文件
    线段树【递归版本】
    Linux 安装 python 指定版本--编译源码方式
    正则表达式高级替换
    【转载】Git忽略规则和.gitignore规则不生效的解决办法
    一次“惊险”的系统修复过程
    YOLO模型对图片中车辆的识别比对
    YOLOv3模型识别车位图片的测试报告(节选)
    在windows下用python调用darknet的yolo接口
  • 原文地址:https://www.cnblogs.com/chy-2003/p/11447428.html
Copyright © 2011-2022 走看看