BZOJ-2729: [HNOI2012]排队(排列组合+高精度
2018-10-16 本文已影响0人
AmadeusChan
题目:http://www.lydsy.com/JudgeOnline/problem.php?id=2729
裸的排列组合,用插空法,先加男生,再加老师,再加女生,易得答案:
Ans( n , m ) = A( n , n ) [ A( 2 , n + 1 ) A( m , n + 3 ) + A( 1 , n + 1 ) A( 2 , 2 ) A( 1 , m ) A( m - 1 , n + 2 ) ]
化简:
Ans( n , m ) = n! ( n + 1 ) [ ( n - m + 4 ) ( n - m + 5 ) ... ( n + 2 ) ] [ ( n + 3 ) n + 2 m ]
然后就用高精度乘法算就可以啦~
代码:
838ba61ea8d3fd1f3774ac59324e251f95ca5f57.jpg.png
压了4位,速度还是这么慢。。。话说那些100+ms是怎么达到的?难道都是敲了FFT!!!?
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std ;
#define MAXN 3010
#define MAX 10000
struct BigNumber {
int a[ MAXN ] , m ;
void Transform( int t ) {
m = 0 ;
if ( ! t ) {
a[ m = 1 ] = 0 ;
} else {
for ( ; t ; t /= MAX ) a[ ++ m ] = t % MAX ;
}
}
void Print( ) {
for ( int i = m ; i ; i -- ) {
if ( i != m ) {
if ( a[ i ] < 1000 ) printf( "0" ) ;
if ( a[ i ] < 100 ) printf( "0" ) ;
if ( a[ i ] < 10) printf( "0" ) ;
}
printf( "%d" , a[ i ] ) ;
}
printf( "\n" ) ;
}
} ans , rec ;
int n , m ;
BigNumber Multiply( BigNumber x , BigNumber y ) {
BigNumber ret ; ret.m = 0 ;
memset( ret.a , 0 , sizeof( ret.a ) ) ;
for ( int i = 0 ; i ++ < x.m ; ) {
for ( int j = 0 ; j ++ < y.m ; ) {
ret.a[ i + j - 1 ] += x.a[ i ] * y.a[ j ] ;
ret.m = max( ret.m , i + j - 1 ) ;
for ( int k = i + j - 1 ; ret.a[ k ] >= MAX ; k ++ ) {
ret.a[ k + 1 ] += ret.a[ k ] / MAX ;
ret.a[ k ] %= MAX ;
ret.m = max( ret.m , k + 1 ) ;
}
}
}
return ret ;
}
int main( ) {
scanf( "%d%d" , &n , &m ) ;
ans.Transform( 1 ) ;
for ( int i = 0 ; i ++ < n ; ) {
rec.Transform( i ) ;
ans = Multiply( ans , rec ) ;
}
rec.Transform( n + 1 ) ;
ans = Multiply( ans , rec ) ;
for ( int i = n - m + 4 ; i <= n + 2 ; i ++ ) {
rec.Transform( i ) ;
ans = Multiply( ans , rec ) ;
}
rec.Transform( ( n + 3 ) * n + 2 * m ) ;
ans = Multiply( ans , rec ) ;
ans.Print( ) ;
return 0 ;
}