您的位置:首页 > 其它

hdu 5446 lucas + 中国剩余定理 + 快速乘 (快速乘板子,中国剩余定理板子,lucas最新板子)

2018-02-14 18:33 471 查看
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

On the first line there is an integer T(T≤20) representing the number of test cases.

Each test case starts with three integers n,m,k(1≤m≤n≤1018,1≤k≤10) on a line where k is the number of primes. Following on the next line are k different primes p1,...,pk. It is guaranteed that M=p1⋅p2⋅⋅⋅pk≤1018 and pi≤105 for every i∈{1,...,k}.

Output

For each test case output the correct combination on a line.

Sample Input

1

9 5 2

3 5

Sample Output

6

题意:M=p1*p2*…pk;求C(n,m)%M,pi小于10^5,n,m,M都是小于10^18。 pi为质数

题解:首先M=x*pi(1<=i<=k)

M不一定是质数 所以只能用Lucas定理求k次 C(n,m)%Pi得到 B[i];

最后会得到一个同余方程组

x≡B[0](mod p[0])

x≡B[1](mod p[1])

x≡B[2](mod p[2])

……

解这个同余方程组 用中国剩余定理

但ll*ll都会爆所以用快速乘

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
const int N = 1e5;
ll prim[N+100],B[N+100];
ll fac[N+100];

void init(ll p)
{
fac[0]=1;
for(int i=1;i<=p;i++)
fac[i]=(fac[i-1]*i)%p;
}

ll qpow(ll a,ll b,ll p)
{
a%=p;
ll res=1;
while(b)
{
if(b&1) res=res*a,res%=p;
a*=a;
a%=p;
b>>=1;
}
return res;
}

ll C(ll n,ll m,ll p)
{
if(m>n) return 0;
return fac
*qpow(fac[m],p-2,p)%p*qpow(fac[n-m],p-2,p)%p;
}

ll lucas(ll n,ll m,ll p)
{
if(m==0) return 1;
else return (C(n%p,m%p,p)*lucas(n/p,m/p,p))%p;
}

ll exgcd(ll a,ll b,ll &x,ll &y)
{
ll d;
if(b==0) {x=1;y=0;return a;}
d=exgcd(b,a%b,y,x);
y-=a/b*x;
return d;
}

ll fast_multi(ll m, ll n, ll mod)//快速乘法
{
ll ans = 0;//注意初始化是0,不是1
while (n)
{
if (n & 1)
ans += m;
m = (m + m) % mod;//和快速幂一样,只不过这里是加
m %= mod;//取模,不要超出范围
ans %= mod;
n >>= 1;
}
return ans;
}

ll CTF(ll b[], ll w[], ll len)
{
ll i,d,x,y,m,n,ret;
ret=0;n=1;
for(i=0;i<len;i++) n*=w[i];
for(i=0;i<len;i++)
{
m=n/w[i];
d=exgcd(w[i],m,x,y);
ll re=fast_multi(y,m,n);
re=fast_multi(re,b[i],n);
// ret=(ret+(y*m%n)*b[i])%n;
ret+=re;re%=n;
}
return (n+ret%n)%n;
}

int main()
{
int t;
scanf("%d",&t);
while(t--)
{
ll n,m;int k;
scanf("%lld%lld%d",&n,&m,&k);
for(int i=0;i<k;i++)
{
scanf("%lld",&prim[i]);
init(prim[i]);
B[i]=lucas(n,m,prim[i]);
}
printf("%lld\n",CTF(B,prim,k));
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: