HDU-3944 DP?(组合数求模)
一、题目链接
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?(组合数求模)的更多相关文章
- hdu 3944 DP? 组合数取模(Lucas定理+预处理+帕斯卡公式优化)
DP? Problem Description Figure 1 shows the Yang Hui Triangle. We number the row from top to bottom 0 ...
- HDU-5226 Tom and matrix(组合数求模)
一.题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=5226 二.题意 给一个大矩阵,其中,$a[i][j] = C_i^j$.输入5个参数,$x_1, ...
- sdut2164Binomial Coeffcients(组合数求模)
http://acm.sdut.edu.cn/sdutoj/problem.php?action=showproblem&problemid=2164 贴一篇写组合数求mod比较好的帖子 这里 ...
- HDU 3944 DP? [Lucas定理 诡异的预处理]
DP? Time Limit: 10000/3000 MS (Java/Others) Memory Limit: 128000/128000 K (Java/Others)Total Subm ...
- HDU 5698 大组合数取模(逆元)
瞬间移动 Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Submis ...
- hdu 3944 dp?
DP? Time Limit: 10000/3000 MS (Java/Others) Memory Limit: 128000/128000 K (Java/Others)Total Subm ...
- HDU 3944 DP? (Lucas定理)
题意:在杨辉三角中让你从最上面到 第 n 行,第 m 列所经过的元素之和最小,只能斜向下或者直向下走. 析:很容易知道,如果 m 在n的左半部分,那么就先从 (n, m)向左,再直着向上,如果是在右半 ...
- 【转载】【转自AekdyCoin的组合数取模】
本篇文章主要介绍了"[组合数求模] 转自AekdyCoin",主要涉及到[组合数求模] 转自AekdyCoin方面的内容,对于[组合数求模] 转自AekdyCoin感兴趣的同学可以 ...
- 【转】AC神组合数取模大全
貌似少了几张图片,不过没有图片也没什么关系的感觉. 最后的究极篇也想出来了,但是貌似找不到题目,好尴尬.. 这个表示的是从n个元素中选取m个元素的方案数. (PS.组合数求模似乎只用在信息学竞赛和 A ...
随机推荐
- QWebEngineView_CssVariables
1.测试代码,参考网址:http://blog.sina.com.cn/s/blog_1508519340102wgq0.html 2.测试下来,结果: 2.1.Qt5.6开始,没有 WebKit了. ...
- 2018-2019-2《网络对抗技术》Exp0 Kali安装 Week1
2018-2019-2<网络对抗技术>Exp0 Kali安装 Week1 Kali的安装 设置虚拟机的名称和操作系统 为虚拟机分配虚拟内存,大小为4096M,分配存储空间,大小为25.0G ...
- ZOJ-3962-数位dp
http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=5594 16进制下的数位dp,由于固定了位数,可以出现前 ...
- oracle表的统计信息完全正确,执行计划无故改变。原厂人员如是回复
就像在电话里提到的那样,Oracle内部的优化器是根据一系列的内部算法基于表上的统计信息来产生执行计划的.对于特别复杂的SQL语句,Oracle的优化器有一定几率不能得到最优的执行计划(因为机器代码实 ...
- div固定顶部和底部
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- linux 命令-case
case 命令作用: case语句使用于需要进行多重分支的应用情况 case 命令使用场景 在shell中的case结构与C/C++中的switch结构是相同的. 它允许通过判断来选择代码块中多条路径 ...
- 201621123006 《Java程序设计》第7周学习总结
1. 本周学习总结 1.1 思维导图:Java图形界面总结 1.2 可选:使用常规方法总结其他上课内容. 窗体事件:一般做最外层容器 鼠标事件:按下.松开.单击 键盘事件:按下.释放 动作事件:不代表 ...
- linux下部署tomcat服务器之安装tomcat
下载tomcat压缩包 apache-tomcat-7.0.82.tar.gz 在把包放到linux 的softwore文件夹下 自己选择文件夹 tar -zxvf apache-tomcat-7. ...
- New Concept English Two 7
$课文14 你会讲英语吗? 133. I had an amusing experience last year. 去年我有过一次有趣的经历. 134. After I had left a smal ...
- HDU 3986
http://acm.hdu.edu.cn/showproblem.php?pid=3986 从开始的最短路里依次删一条边,求新的最短路,求最长的最短路 删边操作要标记节点以及节点对应的边 #incl ...