坑点:
注意起点和终点也算。
(盗图自http://www.cnblogs.com/simplekinght/p/6986268.html?utm_source=itdadao&utm_medium=referral)
解释一下这个样例2:
根据图中我们的标记,我们得知两种走法,(从终点到起点)先斜上,再上。或者先上,再斜上。
而选择这其中的哪一个呢?依据m的位置而定,如果m>=n/2 那么自然是先上。
下面我们考虑
m<=n/2
的情况。
ans(4,2)=c(4,2)+c(3,1)+c(2,0)+4−2
这个式子很明显。
然后我们考虑推广形式
ans(i,j)
ans(i,j)=c(i,j)+c(i−1,j−1)+c(i−2,j−2)...c(i−j+1,1)+c(i−j,0)+i−j
这个要是算的话,复杂度还是蛮高的,跟m相关,所以试着化简。
根据递推式:
cji=cji−1+cj−1i−1
所以,我们把
c(i−j,0)
换成
c(i−j+1,0)
,我们知道这两个都等于1,可以换,然后我们就可以化简了。
注意:
lucas定理在使用的过程中求c(i,j)的工程中需要提前预处理出阶乘取模的答案,然后用的时候直接算阶乘取模的逆元。否则会t。
注意在使用的过程中,n大于等于m。
#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#include<map>
#define inf 0x3f3f3f3f
typedef long long int lli;
using namespace std;
int mod;
const int maxn = 1e4+20;
bool isprime[maxn];int prime[maxn];
void moblus(){
int cnt = 0;
for(lli i = 2;i < maxn;i++){
if(!isprime[i]) prime[cnt++] = i;
for(lli j = 0;cnt&&i*prime[j] < maxn;j++){
int x = prime[j];
isprime[i*x] = 1;
if(i%x == 0) break;
}
}
}
int fac[10010][10010];
int inv[10010][10010];
inline lli qp(lli a,lli x){
lli ans = 1;a%=mod;
for(;x;x>>=1){
if(x&1) ans = ans*a%mod;
a = a*a%mod;
}
return ans%mod;
}
lli c(lli n,lli m){
if(m>n) return 0;
lli ans = 1;
/*
for(int i=1;i<=m;i++){//用逆元递推的求c(n,m) mod是素数 且a与mod 互质 a^(p-1) = 1
lli a = (n+i-m)%mod;
lli b = i%mod;
ans = ans*(a*qp(b,mod-2)%mod)%mod;
}
*/
ans = (lli)fac[mod][n] * qp((lli)fac[mod][n-m]*(lli)fac[mod][m],mod-2)%mod;//预处理的p对x!的取模
return ans;
}
lli lucas(lli n,lli m){
if(m==0) return 1;
return c(n%mod,m%mod)*lucas(n/mod,m/mod)%mod;
}
int main(){
lli t,n,m;int ncase = 0;
moblus();
for(int i = 2;i < 10010;i++){
if(isprime[i]==0){
fac[i][0]=1;
for(lli j = 1;j < 10010;j++){
fac[i][j] = (lli)fac[i][j-1]*j%i;
if(fac[i][j]==0) break;
}
}
}
while(~scanf("%lld%lld%d",&n,&m,&mod)){
ncase++;
if(m>=n/2) m=n-m;
printf("Case #%d: %lld\n",ncase,((lucas(n+1,m)+n-m)%mod+mod)%mod);
}
return 0;
}