一、题目链接

  http://acm.hdu.edu.cn/showproblem.php?pid=3944

二、题意

  给一个巨大的杨辉三角,采用类似DP入门题“数字三角形”的方式求从顶点$(0, 0)$到指定点$(n, k)$的最小累加和,输出最小累加和$%p$的结果。其中,$0 \le k \le n \le 10^9,\ p < 10^4,\ and\ p\ is\ a\ prime$。

三、思路

  一看到数据范围如此之大,直接DP是不行的了。那么就要考虑转换思维和方法,找找规律。先看一张组合数表。

  

  从左下部分的杨辉三角中可以看出,从顶点$(0, 0)$到指定点$(n, k)$的最小累加和,一定是走边上。因为边上的数值最小。研究题目给样例可以发现,从顶点$(0, 0)$到$(4, 2)$是由$C_0^0 + C_1^0 + C_2^0 + C_3^1 + C_4^2 = 1+1+1+3+6 = 12$这么来的,由此可以发现一个规律:从顶点$(0, 0)$到指定点$(n, k)$的最小累加和,是先走$n-k$步竖直向下的,每步取最小值$1$,然后再斜向下走一直到$(n, k)$,累加和为$\sum\limits_{i=0}^kC_{n-k+i}^i$。

  另外,我们可以发现,当$k>\frac{n}{2}$时,先斜向下走到$(k, k)$,再竖直向下走到$(n, k)$,路径上的数值累加和是最小的。由上一篇题解(HDU5226)推导的式子可知,$\sum\limits_{i=k}^{n}C_i^k = C_{n+1}^{k+1} - C_{k}^{k+1} =  C_{n+1}^{k+1}$。

  找出规律以后,还有一个问题,对于上述一种情况($k \le \frac{n}{2}$),当$(n, k)$点非常靠右下方的时候,即大约$n \ge 10^8, k \ge 10^8$时,循环累加斜线方向的每一个数值,计算量太大,会超时。所以还需要继续找规律。仔细观察,可以发现,

  当$j \ge 1$时,$\sum\limits_{i=j}^{k}C_{n-k+i}^i = C_{n+1}^{k} - C_{n-k}^{j-1}$

  否则,当$j = 0$时,$\sum\limits_{i=j}^{k}C_{n-k+i}^i = C_{n+1}^{k}$

  由上规律可知:

  当$k\le \frac{n}{2}$时,先斜向下走到$(n-k, k)$,再竖直向下走到$(n, k)$的最小累加和为\[n-k(从(0, 0)走到(n - k - 1,0))+ \sum\limits_{i=0}^{k}C_{n-k+i}^{i} = (n-k) + C_{n+1}^{k}\]

  当$k > \frac{n}{2}$时,先斜向下走到$(n-k, k)$,再竖直向下走到$(n, k)$的最小累加和为\[k(从(0, 0)走到(k - 1, k - 1)) + C_{n+1}^{k+1}\]

  有了上面的式子,求组合数取模就是个很简单的问题了,因为会存在$p < \frac{n}{k}$的情况(这个问题的详细解释在上一篇博客(HDU5226)中已经说了),所以需要用lucas定理求解。

四、坑点

  因为这题测试数据量非常大(题目中说了,大约$100000$个测试样例),我们在用lucas定理的时候,每次都需要预处理阶乘模和阶乘模的逆元,单次测试时间复杂度为$O(p)$,总的时间复杂度为$O(10^5 * p)$,大约$10^9$的运算量,绝对超时。所以,需要再想办法。

  因为$p$是素数,且$p < 10^4$,我们用筛法统计$10^4$以内的素数个数可以发现,$10^4$以内,只有1231个素数。所以,我们可以预处理出$10^4$内所有数的阶乘模$10^4$内所有素数的数组。但是,素数是离散的,所以,这里需要把所有素数做一下离散化操作。这时,$10^4$内所有数的阶乘模$10^4$内所有素数的数组大小最小是$10^4 * 1231 = 12310000$,如果数据类型为long long,然后再在预处理$10^4$内所有数的阶乘模$10^4$内所有素数的数组的同时预处理出$10^4$内所有数的阶乘模$10^4$内所有素数的逆元数组,大小也是$10^4 * 1231 = 12310000$,加起来就是$2 * 8 * 12310000$个byte,显然会爆内存。解决办法有两个:(1)不要预处理$10^4$内所有数的阶乘模$10^4$内所有素数的逆元数组,需要用逆元时,做一次时间复杂度为$O(log\ p)$的费马小定理或者扩展欧几里得算法;(2)因为$p < 10^4$,所以,可以把数组的数据类型改为int。其实最优的办法是,综合方法(1)和(2)。

五、源代码

  

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define MAXP 10010
using namespace std;
typedef int LL;
LL n, k, p, facts[MAXP][];
int mp[MAXP], rmp[MAXP], buf[MAXP];
bool is[MAXP];
LL qpow(LL a, LL x, LL mod) {
    LL res = ;
    ) {
        )res = (res * a) % mod;
        a = (a * a) % mod;
        x >>= ;
    }
    return res;
}

void init() {
    fill();
    ] = ] = false;
    ;
    ; i < MAXP; ++i) {
        if(is[i]) {
            for(int j = i + i; j < MAXP; j += i)is[j] = false;
            mp[i] = cnt, rmp[cnt] = i;
            cnt++;
        }
    }

    ; k < cnt; ++k) {
        LL mod = rmp[k];
        facts[][k] = ;
        ; i < MAXP; ++i) {
            facts[i][k] = (facts[i - ][k] * i) % mod;
        }
    }
}

LL C(LL n, LL m) {
    ;
    );
    )return n % p;
    , p) % p * qpow(facts[n - m][mp[p]], p - , p) % p;
}

LL lucas(LL n, LL m) {
    if(n < p && m < p)return C(n, m);
    else return lucas(n / p, m / p) * lucas(n % p, m % p) % p;
}

int main() {
#ifndef ONLINE_JUDGE
    freopen("input.txt", "r", stdin);
#endif // ONLINE_JUDGE
    ;
    init();
    while(~scanf("%I64d %I64d %I64d", &n, &k, &p)) {
        LL ans = ;
        )ans = (n + ) % p;
        )ans = ((n - k) % p + lucas(n + , k) % p) % p;
        , k + ) % p) % p;
        printf("Case #%d: %I64d\n", T++, ans);
    }
    ;
}

HDU-3944 DP?(组合数求模)的更多相关文章

  1. hdu 3944 DP? 组合数取模(Lucas定理+预处理+帕斯卡公式优化)

    DP? Problem Description Figure 1 shows the Yang Hui Triangle. We number the row from top to bottom 0 ...

  2. HDU-5226 Tom and matrix(组合数求模)

    一.题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=5226 二.题意 给一个大矩阵,其中,$a[i][j] = C_i^j$.输入5个参数,$x_1, ...

  3. sdut2164Binomial Coeffcients(组合数求模)

    http://acm.sdut.edu.cn/sdutoj/problem.php?action=showproblem&problemid=2164 贴一篇写组合数求mod比较好的帖子 这里 ...

  4. HDU 3944 DP? [Lucas定理 诡异的预处理]

    DP? Time Limit: 10000/3000 MS (Java/Others)    Memory Limit: 128000/128000 K (Java/Others)Total Subm ...

  5. HDU 5698 大组合数取模(逆元)

    瞬间移动 Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submis ...

  6. hdu 3944 dp?

    DP? Time Limit: 10000/3000 MS (Java/Others)    Memory Limit: 128000/128000 K (Java/Others)Total Subm ...

  7. HDU 3944 DP? (Lucas定理)

    题意:在杨辉三角中让你从最上面到 第 n 行,第 m 列所经过的元素之和最小,只能斜向下或者直向下走. 析:很容易知道,如果 m 在n的左半部分,那么就先从 (n, m)向左,再直着向上,如果是在右半 ...

  8. 【转载】【转自AekdyCoin的组合数取模】

    本篇文章主要介绍了"[组合数求模] 转自AekdyCoin",主要涉及到[组合数求模] 转自AekdyCoin方面的内容,对于[组合数求模] 转自AekdyCoin感兴趣的同学可以 ...

  9. 【转】AC神组合数取模大全

    貌似少了几张图片,不过没有图片也没什么关系的感觉. 最后的究极篇也想出来了,但是貌似找不到题目,好尴尬.. 这个表示的是从n个元素中选取m个元素的方案数. (PS.组合数求模似乎只用在信息学竞赛和 A ...

随机推荐

  1. egg.js npm start 启动报错

    开发环境运行项目即npm run dev的时候是正常的,但是npm start会启动失败,最可能的原因是因为npm start启动使用egg-scripts机制启动,对于运行中遇到error日志就会中 ...

  2. 雷林鹏分享:Ruby 发送邮件 - SMATP

    Ruby 发送邮件 - SMATP SMTP(Simple Mail Transfer Protocol)即简单邮件传输协议,它是一组用于由源地址到目的地址传送邮件的规则,由它来控制信件的中转方式. ...

  3. Learn Rails5.2 Bundler ; Forms

    如果一个Rubyer想要提供一个功能或某个程序或程序的集合给其他Rubyer使用,这个Rubyer可以创建一个package,这个package就叫做gems. 可以通过gem install安装. ...

  4. UVALive-3645 Objective: Berlin (最大流:时序模型)

    题目大意:有n个城市,m条航班.已知每条航班的起点和终点,还有每条航班的载客量.出发时间.到达时间.并且要求在任何一个城市(起点.终点除外)都至少要有30分钟的中转时间,求起点到终点的最大客流量. 题 ...

  5. UVA-1610 Party Games (构造)

    题目大意:给出一系列字符串,构造出一个字符串大于等于其中的一半,小于另一半. 题目分析:取大小为中间的两个a,b(a<b).实际上就是找出第一个小于b的同时大于等于a的字符串,直接构造即可.要注 ...

  6. BZOJ1228 [SDOI2009]E&D

    蒟蒻不会= = 话说写题解的巨巨也只会打表233 反正先A掉再说 /************************************************************** Pro ...

  7. <NET CLR via c# 第4版>笔记 第6章 类型和成员基础

    6.1 类型的各种成员 6.2 类型的可见性 public 全部可见 internal 程序集内可见(如忽略,默认为internal) 可通过设定友元程序集,允许其它程序集访问该程序集中的所有inte ...

  8. 判断一棵树是否为二叉搜索树(二叉排序树) python

    输入一棵树,判断这棵树是否为二叉搜索树.首先要知道什么是排序二叉树,二叉排序树是这样定义的,二叉排序树或者是一棵空树,或者是具有下列性质的二叉树: (1)若左子树不空,则左子树上所有结点的值均小于它的 ...

  9. Swift 图片浏览器

    class ViewController: UIViewController, UIScrollViewDelegate{ var scrollView: UIScrollView? var imag ...

  10. 這是我既C語言作業寫博客後寫的第一篇博客

    這篇博客應該算是寫給我自己的博客吧,所以這裏我想用繁體字寫,因為我漸漸地發現我已經很少使用到繁體字了,日常QQ聊天都使用簡體字,繁體字都懶得切換了,但是為了不讓別人麻煩,在外界交流的時候我會使用簡體字 ...