DP?
题解
看这标题取得,一看就知道不是DP。
我们可以先把每个点的路径长给算出来,根据贪心可知,对于一个点它的最小路径的走法是一定的。
这走法就是向斜上方或正上方一直走到底,然后就沿着1一直走。
如果在中线左方,就是往斜上方走,右方就是往右走。
而走到一的路径也十分好求,
这样用lucas就可以做出来了。
源码
感觉有点卡常。
#include<cstdio>
#include<cmath>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
#include<map>
#include<set>
using namespace std;
typedef long long LL;
const int mo=1e9+7;
const int INF=0x3f3f3f3f;
#define gc() getchar()
template<typename _T>
void read(_T &x){
_T f=1;x=0;char s=gc();
while(s>'9'||s<'0'){if(s=='-')f=-1;s=gc();}
while(s>='0'&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=gc();}
x*=f;
}
int fac[1505][10005],inv[1505][10005];
int prime[10005],cntp,mp[10005];
bool oula[10005];
int qkpow(int a,int s,int p){
int t=1;
while(s){
if(s&1)t=t*a%p;
a=a*a%p;s>>=1;
}
return t;
}
int C(int n,int m,int p){
if(n<m)return 0;if(n==m)return 1;int t=mp[p];
return fac[t][n]*inv[t][m]%p*inv[t][n-m]%p;
//if(n<m)return 0;int up=1,down=1;
//for(int i=n-m+1;i<=n;i++)up=up*i%p;
//for(int i=2;i<=m;i++)down=down*i%p;
//return up*qkpow(down,p-2,p)%p;
}
void init(){
for(int i=2;i<=1e4;i++){
if(!oula[i])prime[++cntp]=i,mp[i]=cntp;
for(int j=i<<1;j<=1e4;j+=i)oula[j]=1;
}
for(int j=1;j<=cntp;j++){
fac[j][0]=inv[j][0]=1;
for(int i=1;i<=1e4;i++)
fac[j][i]=fac[j][i-1]*i%prime[j],inv[j][i]=qkpow(fac[j][i],prime[j]-2,prime[j]);
}
}
int lucas(int n,int m,int p){
if(!m)return 1;
return C(n%p,m%p,p)*lucas(n/p,m/p,p)%p;
}
signed main(){
int n,m,p,tt=0;init();
while(scanf("%d %d %d",&n,&m,&p)!=EOF){
printf("Case #%d: ",++tt);
if(m<=n/2)printf("%d\n",(lucas(n+1,m,p)+n-m)%p);
else printf("%d\n",(lucas(n+1,m+1,p)+m)%p);
}
return 0;
}
/*
1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
1 5 10 10 5 1
1 6 15 20 15 6 1
1
2 2
3 4 3
4 6 6 4
5 8 12 8 5
6 10 18 18 10 6
*/