toj 4111 组合数取模 暴力分解
题目大意:组合数取模,n和m并不算大,p比较大且是合数。
思路:暴力分解+快速幂
注:暴力也是有区别的,分解质因数时可以用以下work函数,写的非常巧妙,摘录自互联网。
1 #include <iostream> 2 #include <cstring> 3 using namespace std; 4 5 typedef long long ll; 6 const ll mod = 1ll << 32; 7 const int N = 1000001; 8 const int M = 100007; 9 bool is_prime[N]; 10 int prime[M]; 11 int p; 12 13 void get() 14 { 15 memset( is_prime, true, sizeof(is_prime) ); 16 is_prime[0] = is_prime[1] = false; 17 for ( int i = 2; i < N; i++ ) 18 { 19 if ( is_prime[i] ) 20 { 21 int j = i * i; 22 if ( j >= N ) break; 23 do 24 { 25 is_prime[j] = false; 26 j += i; 27 } while ( j < N ); 28 } 29 } 30 p = 0; 31 for ( int i = 0; i < N; i++ ) 32 { 33 if ( is_prime[i] ) 34 { 35 prime[p++] = i; 36 } 37 } 38 } 39 40 ll pow_mod( ll a, ll n ) 41 { 42 ll ans = 1; 43 a = a % mod; 44 while ( n ) 45 { 46 if ( n & 1 ) 47 { 48 ans = ans * a % mod; 49 } 50 n = n >> 1; 51 a = a * a % mod; 52 } 53 return ans; 54 } 55 56 ll work( ll n, ll q ) 57 { 58 ll ans = 0; 59 while ( n ) 60 { 61 ans += n / q; 62 n /= q; 63 } 64 return ans; 65 } 66 67 ll c( ll n, ll m ) 68 { 69 ll ans = 1; 70 for ( int i = 0; i < p && prime[i] <= n; i++ ) 71 { 72 ll x = work( n, prime[i] ); 73 ll y = work( n - m, prime[i] ); 74 ll z = work( m, prime[i] ); 75 x = x - ( y + z ); 76 ans = ans * pow_mod( prime[i], x ) % mod; 77 } 78 return ans; 79 } 80 81 int main () 82 { 83 get(); 84 int t; 85 cin >> t; 86 while ( t-- ) 87 { 88 ll n, m; 89 cin >> n >> m; 90 cout << c( n, m ) << endl; 91 } 92 return 0; 93 }