题目
发现最短路径是(C_{n}^k + C_{n - 1}^{k - 1} + C_{n - 2}^{k - 2} + dots + C_{n - k} ^ 0 + n - k)
根据帕斯卡公式,(C_{n}^k = C_{n - 1}^k + C_{n - 1}^{k - 1}),将上面的式子变化一下(C_{n - k}^0 = C_{n -k + 1}^0)
就可以得到答案 (C_{n + 1}^k + n - k)
如果直接求卢卡斯,卢卡斯没预处理时的时间复杂度是(O(plog_p^m))会超时,那么需要预处理
p范围是1 - 10000,那么线性筛除1 - 10000的素数有1000多个,(n^2)预处理一下每个素数下的阶乘和逆元
最后卢卡斯(log_p^m)求即可
#include <iostream>
#include <cstdio>
using namespace std;
#define ll long long
const int N = 1e4 + 5;
ll fac[N][N], inv[N][N];
int pri[N], tot, prith[N];
bool vis[N];
void pri_table(int N){
for(int i = 2; i <= N; i++){
if(!vis[i]){
pri[++tot] = i;
prith[i] = tot;
}
for(int j = 1; j <= tot; j++){
if(i * pri[j] > N)break;
vis[i * pri[j]] = 1;
if(i % pri[j] == 0)break;
}
}
}
ll pow(ll a, ll b, ll p){
ll ans = 1; a %= p;
while(b){
if(b & 1)ans = ans * a % p;
a = a * a % p;
b >>= 1;
}
return ans;
}
void init(){
for(int i = 1; i <= tot; i++){
fac[i][0] = inv[i][0] = 1;
for(int j = 1; j <= pri[i]; j++){
fac[i][j] = (fac[i][j - 1] * j) % pri[i];
inv[i][j] = pow(fac[i][j], pri[i] - 2, pri[i]);
}
}
}
ll C(ll n, ll m, ll p){
if(m > n)return 0;
if(m == n)return 1;
int t = prith[p];
return fac[t][n] * inv[t][m] % p * inv[t][n - m] % p;
}
ll lucas(ll n, ll m, ll p){
if(m == 0)return 1;
return C(n % p, m % p, p) * lucas(n / p, m / p, p) % p;
}
int main(){
int n, k, p;
pri_table(10000);
init();
int t = 0;
while(~scanf("%d%d%d", &n, &k, &p)){
if(k >= n / 2)k = n - k;
printf("Case #%d: %lld
", ++t, (lucas(n + 1, k, p) + n - k) % p);
}
return 0;
}