Problem Description
Figure 1 shows the Yang Hui Triangle. We number the row from top to bottom 0,1,2,…and the column from left to right 0,1,2,….If using C(n,k) represents the number of row n, column k. The Yang Hui Triangle has a regular pattern as follows.
C(n,0)=C(n,n)=1 (n ≥ 0)
C(n,k)=C(n-1,k-1)+C(n-1,k) (0<k<n)
Write a program that calculates the minimum sum of numbers passed on a route that starts at the top and ends at row n, column k. Each step can go either straight down or diagonally down to the right like figure 2.
As the answer may be very large, you only need to output the answer mod p which is a prime.
Input
Input to the problem will consists of series of up to 100000 data sets. For each data there is a line contains three integers n, k(0<=k<=n<10^9) p(p<10^4 and p is a prime) . Input is terminated by end-of-file.
Output
For every test case, you should output "Case #C: " first, where C indicates the case number and starts at 1.Then output the minimum sum mod p.
Sample Input
1 1 2
4 2 7
Sample Output
Case #1: 0
Case #2: 5
题目大意
杨辉三角,从第0行第0列,走到第n行第k列,求经过数和的最小值,对p取余。
组合
和最小,肯定多走边上的1,当1走不了的时候,斜着走到终点。因为杨辉三角是对称的,我们把对称轴右边的统一对称到左边。
最小和就是
关键就是求这个组合数
Lucas定理
把n和m表示成p进制数,对p进制下的每一位分别计算组合数,最后再乘起来。
也就是转化成为递归求解。
当m,n<=10000,p<=1e9,用打表的方法( 两层循环预处理)
当m,n<=1e18,p<=1e6,用Lucas定理
预处理
这道题目T最大100000,p比较小,才1e4,如果不预处理,用Lucas发现也超时了???Lucas有个特点,即使一开始的m,n很大,因为取余的缘故,m,n在计算组合数的时候都不会大于p,可以建立个二维表存前缀阶乘和逆元。
fact[i][j]表示阶乘 j ! (mod i)i为质数;inv[i][j]表示阶乘 j ! 的逆元。
这个预处理也是.....???看到TLE就发怵,我宁可一个WA?!
T很大的时候,预处理!
总结
1. 找到规律
2. T很大,要预处理
#include <bits/stdc++.h>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
const int Max = 10010;
int fact[Max][Max],inv[Max][Max];
int num=0,p[Max],vis[Max];
void isprime()
{
for(int i=2;i<Max;i++){
if(!vis[i]){
p[num++] = i;
for(int j=i;j<Max;j+=i){
vis[j] = 1;
}
}
}
}
ll qpow(ll a,ll b,ll mod)
{
ll res = 1;
while(b)
{
if(b&1) res = res*a%mod;
a = a*a%mod;
b>>=1;
}
return res;
}
ll C (ll n,ll m,ll mod)
{
if(m==0) return 1;
return ((fact[mod][n]*inv[mod][m]%mod)*inv[mod][n-m])%mod;
}
ll Lucas(ll n,ll m,ll mod)
{
if(m==0) return 1;
else return( C(n%mod,m%mod,mod)*Lucas(n/mod,m/mod,mod) )%mod;
}
void init()
{
for(int k=0;k<num;k++){
int i = p[k];
fact[i][0] = inv[i][0] = 1;
for(int j=1;j<=i;j++){
fact[i][j] = fact[i][j-1]*j%i;
inv[i][j] = qpow(fact[i][j],i-2,i);
}
}
}
int main()
{
isprime();
init();
ll n,m,mod;
int t=1;
while(~scanf("%lld %lld %lld",&n,&m,&mod))
{
if(m>n-m) m = n-m;
printf("Case #%d: %lld\n",t++,(Lucas(n+1,m,mod)+n-m)%mod);
}
return 0;
}