Saving Beans
Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 5775 Accepted Submission(s): 2320
Now they turn to you for help, you should give them the answer. The result may be extremely huge; you should output the result modulo p, because squirrels can’t recognize large numbers.
Then followed T lines, each line contains three integers n, m, p, means that squirrels will save no more than m same beans in n different trees, 1 <= n, m <= 1000000000, 1 < p < 100000 and p is guaranteed to be a prime.
2 1 2 5 2 1 5
3 3HintHint For sample 1, squirrels will put no more than 2 beans in one tree. Since trees are different, we can label them as 1, 2 … and so on. The 3 ways are: put no beans, put 1 bean in tree 1 and put 2 beans in tree 1. For sample 2, the 3 ways are: put no beans, put 1 bean in tree 1 and put 1 bean in tree 2.
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)
Lucas最大的数据处理能力是p在10^5左右,不能再大了,hdu 3037就是10^5级别的!
对于大组合数取模,n,m不大于10^5的话,用逆元的方法,可以解决。对于n,m大于10^5的话,那么要求p<10^5,这样就是Lucas定理了,将n,m转化到10^5以内解。
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
#define ms(x,y) memset(x,y,sizeof(x))
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 5;
ll fac[maxn];
void init(ll mod) //初始化乘积,优化C(n,m,mod)
{
ll i;
fac[0] =1;
for(i =1; i <= mod; i++)
fac[i] = fac[i-1]*i % mod;
}
ll exp_mod(ll a, ll b, ll mod) //快速幂
{
ll tmp = a % mod, ans =1;
while(b)
{
if(b & 1) ans = ans * tmp % mod;
tmp = tmp*tmp % mod;
b >>=1;
}
return ans;
}
ll C(ll n, ll m, ll mod) //朴素组合数n取m
{
if(m > n)
return 0;
return fac[n]*exp_mod(fac[m]*fac[n-m], mod-2, mod) % mod;//逆元
}
ll Lucas(ll n, ll m, ll mod) //lucas求组合数c n取m
{
if(m ==0)
return 1;
return (C(n%mod, m%mod, mod)*Lucas(n/mod, m/mod, mod))%mod;
}
int main()
{
int t;
scanf("%d", &t);
while (t--)
{
ll n, m, mod;
scanf("%I64d%I64d%I64d", &n, &m, &mod);
init(mod); //注意要初始化乘积
//printf("%I64d\n", C(n+m,m,mod));
printf("%I64d\n", Lucas(n + m, m, mod));
}
return 0;
}
朴素T
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
#define ms(x,y) memset(x,y,sizeof(x))
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 5;
ll quick_pow(ll a, ll b, ll mod) //快速幂
{
ll ans = 1;
a %= mod;
while (b)
{
if (b & 1)
{
ans = ans * a % mod;
}
a = a * a % mod;
b >>= 1;
}
return ans;
}
ll C(ll n, ll m, ll mod) //朴素求组合数n取m
{
if (m > n) return 0;
ll ans = 1;
for (int i = 1; i <= m; i++)
{
ll a = (n + i - m) % mod;
ll b = i % mod;
ans = ans * (a * quick_pow(b, mod - 2, mod) % mod) % mod; //逆元求组合数
}
return ans;
}
ll lucas(ll n, ll m, ll mod) //Lucas求组合数n取m
{
if (m == 0) return 1;
return C(n % mod, m % mod, mod) * lucas(n / mod, m / mod, mod) % mod;
}
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int t;
scanf("%d", &t);
while (t--)
{
ll n, m, mod;
scanf("%I64d%I64d%I64d", &n, &m, &mod);
//printf("%I64d\n", C(n+m,m,mod));
printf("%I64d\n", lucas(n + m, m, mod));
}
return 0;
}
664



被折叠的 条评论
为什么被折叠?



