您的位置:首页 > 理论基础 > 计算机网络

HDU 5446 2015长春站网络赛1010(数论模板题)

2015-09-16 23:10 567 查看
这道题知道两个东西就能写出来:lucas+CRT(中国剩余定理),题目很裸。但是有一个坑,就是相乘的时候会爆LL!!!这个时候用一个快速乘就搞定了,这个也是这道题才学会的,其实快速成很简单,就是把一个数变成2进制,然后把*改成了+法(和快速幂基本一样)。

lucas定理: C(n,m) == C(n/p,m/p)*C(n%p,m%p) (mod p) ,p为素数。

证明可以看cxlove大神的博客:lucas定理的证明

下面直接给出AC代码:

**#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#define LL long long
#define FOR(i,x,y)  for(int i = x;i < y;i ++)
#define IFOR(i,x,y) for(int i = x;i > y;i --)
#define MAXN 110000
using namespace std;
LL fac[MAXN];
//快速幂
LL QuickPow(LL a,LL n,LL mod){
LL ans=1;
while(n){
if(n&1) ans = (ans*a)%mod;
a = (a*a)%mod;
n>>=1;
}
return ans;
}
//快速乘
LL Mul(LL a,LL b,LL mod){
LL ret = 0;
while(b){
if(b&1) ret = (ret+a)%mod;
a = (a+a)%mod;
b >>= 1;
}
return ret;
}
void Get_Fac(LL p){
fac[0] = 1;
for(int i = 1;i <= p;i ++){
fac[i] = fac[i-1]*i;
fac[i] %= p;
}
}
void Ex_Gcd(LL a,LL b,LL& d,LL& x,LL& y){
if(!b)  {d =a; x = 1; y = 0;}
else { Ex_Gcd(b,a%b,d,y,x); y -= x*(a/b);}
}
//lucas定理
LL Lucas(LL n,LL m,LL p){
LL ret = 1;
while(n && m){
LL a = n%p,b = m%p;
if(a < b)   return 0;
ret = Mul(ret,Mul(fac[a],QuickPow(Mul(fac[a-b],fac[b],p),p-2,p),p),p);
ret %= p;
n /= p;
m /= p;
}
return ret;
}
//中国剩余定理 x == a[i] (mod m[i])   共有n个方程。
LL CRT(LL n,LL* a,LL* m){
LL M = 1,d,y,x = 0;
for(int i = 0;i < n;i ++)   M *= m[i];
for(int i = 0;i < n;i ++){
LL  w = M/m[i];
Ex_Gcd(m[i],w,d,d,y);
x = (x + Mul(y,Mul(w,a[i],M),M)) % M;
}
return (x+M)%M;
}
int main()
{
//freopen("test.in","r",stdin);
int T;
scanf("%d",&T);
while(T--){
LL n,m,num,p[15],a[15];
scanf("%I64d%I64d%I64d",&n,&m,&num);
for(int i = 0;i < num;i ++){
scanf("%I64d",&p[i]);
}
for(int i = 0;i < num;i ++){
Get_Fac(p[i]);
a[i] = Lucas(n,m,p[i]);
}
printf("%I64d\n",CRT(num,a,p));
}
return 0;
}**
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: