先样Pascal推一下公式,再用Lucas求值
p较小,且测试数据较多的时候需要打表
#include
#include
#include
using namespace std;
#define row 1300
#define hang 10050
int pos[hang]={0};
int reversal[row][hang]={0};
int remember[row][hang]={0};
int prime[hang],vis[hang],cnt=0;
int exp(int a,int b,int p)
{
int ret=1;
while(b)
{
if(b&1) ret=ret*a%p;
a=a*a%p;
b>>=1;
}
return ret;
}
void init()
{
memset(vis,0,sizeof(vis));
for(int i=2;i<hang;i++)
{
if(!vis[i])
{
prime[cnt++]=i;
pos[i]=cnt;
remember[cnt][0]=reversal[cnt][0]=1;
for(int j=1,k=1;j<i;j++)
{
k=k*j%i;
remember[cnt][j]=k;
reversal[cnt][j]=exp(k,i-2,i);
}
}
for(int j=0;j<cnt&&i*prime[j]<hang;j++)
{
vis[i*prime[j]]=1;
if(i%prime[j]==0) break;
}
}
}
int cnm(int n,int m,int p)
{
if(m>n) return 0;
int idx=pos[p];
int ret=remember[idx][n]*reversal[idx][m]%p;
ret=ret*reversal[idx][n-m]%p;
return ret;
}
int Lucas(int n,int m,int p)
{
if(m==0) return 1;
return cnm(n%p,m%p,p)*Lucas(n/p,m/p,p)%p;
}
int main()
{
int cas=1,n,m,p;
init();
while(~scanf("%d %d %d",&n,&m,&p))
{
if(2*m>n) m=n-m;
printf("Case #%d: %d\n",cas++,((Lucas(n+1,m,p)+n-m)%p+p)%p);
}
return 0;
}
以下是未打表的方式
#include
#include
#include
using namespace std;
typedef long long ll;
ll power(ll p,ll e,ll m)
{
ll d=1,t=p;
while(e>0)
{
if(e&1) d=(d*t)%m;
e/=2;
t=(t*t)%m;
}
return d;
}
ll cm(ll n,ll m,ll p)
{
ll i,ans=1,a,b;
for(i=0;i<m;i++)
{
a=(n-i)%p;
b=(m-i)%p;
ans=ans*(a*power(b,p-2,p)%p)%p;
}
return ans;
}
ll Lucas(ll n,ll m,ll p)
{
if(m==0) return 1;
return cm(n%p,m%p,p)*Lucas(n/p,m/p,p)%p;
}
int main()
{
ll n,m,p;
int cas=1;
while(~scanf("%lld %lld %lld",&n,&m,&p))
{
if(2*m>n) m=n-m;
printf("Case #%d %lld\n",cas++,(((Lucas(n+1,m,p)+n-m)%p+p)%p));
}
return 0;
}