HDU3944-DP?(Lucas定理+预处理)

题目链接

Problem Description

https://i-blog.csdnimg.cn/blog_migrate/68ba60d4a793fa9a0a3fbdbcccd96a3f.jpeg


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走不了的时候,斜着走到终点。因为杨辉三角是对称的,我们把对称轴右边的统一对称到左边。

最小和就是C_{n-m}^{0}+ C_{n-m+1}^{1}+C_{n-m+2}^{2}+C_{n-m+3}^{3}+...+C_{n}^{m}+n-m

=C_{n-m+1}^{0}+ C_{n-m+1}^{1}+C_{n-m+2}^{2}+C_{n-m+3}^{3}+...+C_{n}^{m}+n-m

=C_{n-m+2}^{1}+C_{n-m+2}^{2}+C_{n-m+3}^{3}+...+C_{n}^{m}+n-m

=C_{n-m+3}^{2}+C_{n-m+3}^{3}+...+C_{n}^{m}+n-m

=C_{n-m+4}^{3}+...+C_{n}^{m}+n-m

=C_{n+1}^{m}+n-m

关键就是求这个组合数

Lucas定理

C_{n}^{m}=C_{n \ mod \ p}^{m\ mod\ p}*C_{n/p}^{m/p} \ (mod\ p)

把n和m表示成p进制数,对p进制下的每一位分别计算组合数,最后再乘起来。

也就是转化成为递归求解。

求组合数的四种方法

当m,n<=10000,p<=1e9,用打表的方法(C_{n}^{m}=C_{n-1}^{m-1}+C_{n-1}^{m} 两层循环预处理)

当m,n<=1e18,p<=1e6,用Lucas定理

预处理

这道题目T最大100000p比较小,才1e4,如果不预处理,用Lucas发现也超时了???Lucas有个特点,即使一开始的m,n很大,因为取余的缘故,m,n在计算组合数的时候都不会大于p,可以建立个二维表存前缀阶乘和逆元。

fact[i][j]表示阶乘 j ! (mod i)i为质数;inv[i][j]表示阶乘 j ! 的逆元。

这个预处理也是.....???看到TLE就发怵,我宁可一个WA?!

T很大的时候,预处理!

总结

1. 找到规律 C_{n+1}^{m}+n-m

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;
}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值