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 }

你可能感兴趣的:(组合)