Problem Description
On the way to the next secret treasure hiding place, the mathematician discovered a cave unknown to the map. The mathematician entered the cave because it is there. Somewhere deep in the cave, she found a treasure chest with a combination lock and some numbers on it. After quite a research, the mathematician found out that the correct combination to the lock would be obtained by calculating how many ways are there to pick
m different apples among
n of them and modulo it with
M .
M is the product of several different primes.
Input
Output
For each test case output the correct combination on a line.
Sample Input
Sample Output
Source
2015 ACM/ICPC Asia Regional Changchun Online
题意:M=p1*p2*...pk;求C(n,m)%M,pi小于10^5,n,m,M都是小于10^18。
分析:Lucas定理求C(n,m)%M,而中国剩余定理刚好解决后面部分。利用Lucas定理求出所有对pi取模的值,然后在用中国剩余定理求解。
Lucas定理不懂的可以
戳这里;
中国剩余定理不懂的可以
戳这里;
扩展欧几里德算法的话可以
戳这里。
Ps. 刚开始学数论,这个题我看了三天博客,才略懂略懂,只能说数论这东西真尼玛难 - -
#include <iostream>
#include <cstdio>
#include <cstring>
#include <stack>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include <cmath>
#include <algorithm>
using namespace std;
const double eps = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
const int MOD = 1000000007;
#define ll long long
#define CL(a) memset(a,0,sizeof(a))
const int maxn = 1e5 + 5;
ll fac[maxn]={0,1},inv[maxn]={0,1};
ll pow_mod(ll a, ll n, ll mod)//快速幂取模
{
ll ret = 1;
while (n)
{
if (n&1)
ret = ret*a%mod;
a = a*a%mod;
n >>= 1;
}
return ret;
}
ll Lucas(ll n, ll m, ll mod)//Lucas定理
{
ll ret=1;
ll mm=m,nn=n;
while (mm && nn)
{
ll mod_m=mm%mod, mod_n=nn%mod;
if (mod_n>=mod_m)
ret = ret*fac[mod_n]%mod*inv[mod_m]%mod*inv[mod_n-mod_m]%mod;
else
{
ret = 0;
break;
}
mm/=mod;
nn/=mod;
}
return ret;
}
void exgcd(ll a, ll b, ll &d, ll &x, ll &y)//扩展欧几里德求逆元
{
if (b == 0)
d = a, x = 1, y = 0;
else
{
exgcd(b, a%b, d, y, x);
y -= x * (a / b);
}
}
ll china(ll n, ll m[], ll a[])//中国剩余定理求解
{
ll aa = a[0];
ll mm = m[0];
for (int i=0; i<n; i++)
{
ll sub = (a[i] - aa);
ll d, x, y;
exgcd(mm, m[i], d, x, y);
if (sub % d) return -1;
ll new_m = m[i]/d;
new_m = (sub/d*x%new_m+new_m)%new_m;
aa = mm*new_m+aa;
mm = mm*m[i]/d;
}
aa = (aa+mm)%mm;
return aa;
}
int main ()
{
int cas;
ll n, m, k, a[15], p[15];
scanf("%d", &cas);
while (cas--)
{
scanf("%lld%lld%lld",&n,&m,&k);
for (int i=0; i<k; i++)
{
scanf("%lld",&p[i]);
//init(p[i]);
for (int j=2; j<p[i]; j++)
fac[j] = fac[j-1]*j%p[i];
inv[p[i]-1] = pow_mod(fac[p[i]-1], p[i]-2, p[i]);
for (int j=p[i]-1; j>0; j--)
inv[j-1] = inv[j]*j%p[i];
a[i] = Lucas(n, m, p[i]);
}
printf("%lld\n",china(k, p, a));
}
return 0;
}