现在的位置: 首页 > 综合 > 正文

HDOJ–3037–Saving Beans【数论】

2018年04月24日 ⁄ 综合 ⁄ 共 1311字 ⁄ 字号 评论关闭

题意:把不多于m个豆子存在n棵树上。豆子取到m,把多余的豆子存在第n+1棵树上,就转换成了把m个豆子存在n+1棵树上的排列组合问题,答案为C(n+m,m)

Lucas定理:

A、B是非负整数,p是质数。AB写成p进制:A=a[n]a[n-1]...a[0],B=b[n]b[n-1]...b[0]。
则组合数C(A,B)与C(a[n],b[n])*C(a[n-1],b[n-1])*...*C(a[0],b[0])  mod p同余
即:Lucas(n,m,p)=c(n%p,m%p)*Lucas(n/p,m/p,p) 

然后粘一段在别人解题报告里看到的证明:

以求解n! % p为例,把n分段,每p个一段,每一段求的结果是一样的。但是需要单独处理每一段的末尾p, 2p, ...,把p提取出来,会发现剩下的数正好又是(n / p)!,相当于划归成了一个子问题,这样递归求解即可。
这个是单独处理n!的情况,当然C(n,m)就是n!/(m!*(n-m)!),每一个阶乘都用上面的方法处理的话,就是Lucas定理了

乘法逆元:满足a*k≡1 (mod p)的k值就是a关于p的乘法逆元。

如果N和P互质,由费马小定理知(N^(P-1))%P=1,所以N与N^(P-2)互为乘法逆元。

#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <vector>
#include <set>
#include <queue>
#include <stack>
#define PI acos(-1)
using namespace std;
#define N 100005
long long int f[N];
long long int mode(long long int a,long long int n,long long int p)
{
	long long int t = a;
	long long int ans = 1;
	while(n)
	{
		if(n & 1)
			ans = (ans * t) % p;
		n >>= 1;
        t =  (t * t) % p;
	}
	return ans;
}

long long int C(long long int n,long long int m,long long int p)
{
    if(n<m) return 0;
    return f[n]*mode((f[n-m]*f[m])%p,p-2,p)%p;
}
long long int Lucas(long long int n,long long int m,long long int p)
{
    if(m==0)    return 1;
    return (C(n%p,m%p,p)*Lucas(n/p,m/p,p))%p;
}

int main()
{
    int t;
    long long int n,m,p;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%I64d%I64d%I64d",&n,&m,&p);
        f[0]=1;
        for(int i=1;i<=p;i++)
            f[i]=f[i-1]*i%p;
        printf("%I64d\n",Lucas(n+m,m,p));
    }
    return 0;
}

【上篇】
【下篇】

抱歉!评论已关闭.