预备知识:
一: a*b%c=(a%c)*(b%c)%c
a^b%p=(a%p)^b%p
a/b%p=a*(b^p-2)%p (如果b和p是互质的话,可用费马小定理来写)
二: 快速幂 求a^b(思想是二分法)
a^6=a*a*a*a*a*a
a^6=(a*a*a)^2这样二分后,计算的次数大大减少了
代码如下:
long long q_pow(int a,int b)//快速幂计算 a^b%p
{
int ans=1;
if(b==0)
return 1;
while(b)
{
if(b&1)//如果b是奇数
{
ans*=a%p;
}
b>>=1;//相当于b/=2
a*=a%p;
}
return ans;
}
三:Lucas定理 C(n,m)%p,其中p必须为素数,且范围在p<1e5。适用于n,m非常大的时候
可得递归式(C(n%p, m%p)*Lucas(n/p, m/p))%p
C(n,m)%p=C(n/p,m/p)*C(n%p,m%p)%p
具体代码:
//Lucas定理 组合数学取模 C(n,m)%p=C(n/p,m/p)*C(n%p,m%p)%p 递推公式为:C(n,m)%p=(C(n%p,m%p)*Lucas(n/p,m/p))%p
//费马小定理:假如p是质数,且gcd(a,p)=1,那么 a(p-1)≡1(mod p)。
//即:假如a是整数,p是质数,且a,p互质(即两者只有一个公约数1),那么a的(p-1)次方除以p的余数恒等于1。
//a*b%c=(a%c)*(b%c)%c a^n%p=(a%p)^n%p
#include
using namespace std;
const int N=1e5;
long long fac[N];//数组计算阶乘模p
long long n,m,p;
void init()
{
fac[0]=1;fac[1]=1;
for(int i=2;i<=p;i++)
{
fac[i]=fac[i-1]*i%p;
}
}
long long q_pow(int a,int b)//快速幂计算 a^b
{
int ans=1;
if(b==0)
return 1;
while(b)
{
if(b&1)//如果b是奇数
{
ans*=a%p;
}
b>>=1;//b/=2
a*=a%p;
}
return ans;
}
long long C(int n,int m)//计算 C(n%p,m%p)%p(这里的C是组合中的)
{
if(m>n)
return 0;
else
return fac[n]*q_pow((fac[m]*fac[n-m]),p-2)%p;
}
long long Lucas(int n,int m)
{
if(m==0)
return 1;
else
return C(n%p,m%p)*Lucas(n/p,m/p)%p;
}
int main()
{
int t;
cin>>t;
while(t--)
{
cin>>n>>m>>p;
init();
cout<
}
注意:当n,m很小时,可以用递归来做:C(n,m)=C(n-1,m)+C(n-1,m-1)或者之前用到的乘法逆元法
(a%c)*(b%c)%c仍然越界的话
#include2 #include 3 using namespace std; 4 5 __int64 Pow(__int64 a, __int64 b, __int64 c) 6 { 7 a %= c; 8 b %= c; 9 __int64 ret = 0; //计录(a*b)%c的值。 10 while(b) 11 { 12 if(b&1) 13 ret += a, ret %= c; 14 a <<= 1; a %= c; //a随着b中二进制位数而扩大每次扩大两倍。 15 b >>= 1; //b来缩小两倍 去掉最后一位 由于当前最后一位我们用完了, 16 } 17 return ret; 18 } 19 20 int main() 21 { 22 __int64 a, b, c; 23 while(~scanf("%I64d%I64d%I64d", &a, &b, &c)) 24 { 25 printf("%I64d\n", Pow(a, b, c)); 26 } 27 return 0; 28 }