hdu 3944 DP? 组合数学与数论的结合
来源:互联网 发布:管家婆软件不能折旧 编辑:程序博客网 时间:2024/06/06 05:02
原题连接:http://acm.hdu.edu.cn/showproblem.php?pid=3944
题目大意:求杨辉三角中从塔尖到n行k列所经过的路径中,虽经过数字之和最小的一条路
经过观察,很容易想到的一个结论就是,这个最小值是从定点开始,然后到合适的位置45度斜着走到(n,k)的位置,也就是
//c(m,n) 表示n中选m个
c(0,n-k)+c(1,n-k+1)+c(2,n-k+2) + ...... + c(k,n) + n - k;
现在的关键就是求前面的那些组合数的和的公式
当时,我并不知道c(0,n-k)+c(1,n-k+1)+c(2,n-k+2) + ...... + c(k,n) 的公式
然后我就用组合数学的式子证明了,c(0,n-k)+c(1,n-k+1)+c(2,n-k+2) + ...... + c(k,n) = c(k,n+1)
证明过程如下:
有G{c(k,n+k)} = 1 / (1-x)^(n+1);这个是组合数学里面关于生成函数的式子
现在我们有:G{c(m,n-k+m)} = 1 / (1-x)^(n-k+1)
即:c(m,n-l+m) 的生成函数是 A(x) = 1 / (1-x)^(n-k+1);
令:B(x) = A(0) + A(1) + A(2) +.....+A(x)
则:B(x) = A(x)/(1-x) = 1 / (1 - k)^(n-k+2); //这个是生成函数的一个重要性质
再次使用G{c(k,n+k)} = 1 / (1-x)^(n+1)
就可以求得:B(x) = G{c(k,n - k+1)} 所以B(x)的第k项的系数为c(k,n+1)
我原以为这个到这儿就要结束了,总结上面的就是,结果为 (c(k,n+1)+n-k) modp
哎,我刚刚学习数学啊,还是太幼稚了
由于n和k的值都很大,也就是说,求c(k,n+1)的时候还是一个很大的麻烦,怎么求呢??
这儿就有了一个 Lucas定理
定理是这样的:
A、B是非负整数,p是质数。AB写成p进制:A=a[n]a[n-1]...a[0],B=b[n]b[n-1]...b[0]。
则组合数C(A,B)与C(a[n],b[n])*C(a[n-1],b[n-1])*...*C(a[0],b[0])
Lucas定理的证明用到了数论的知识,我的数论还在起步的状态,我没有看懂!
然后就是求组合数连乘了
但是当我敲进了一个模板的时候,tle,我傻眼了,原来这个题需要预处理一下,因为,这儿的数据规模太大了
下面的东西,我看的那个解题报告我没看懂,包含的内容如下:筛素数,素数阶乘模逆 好像是这样的,我由于数论还没有看多少,没看懂
我是第一次推导这样的公式,如有不妥的地方,还望多多交流
贴一个代码吧:
#include <cstdio>#include <cstring>#include <vector>#define maxn 10000using namespace std;int flag[maxn],pim[maxn],tol;int p[1229][9973];int ni[1229][9973];int mp[10000];void init(){ tol=0; for(int i=2; i<maxn; i++) //素数筛 { if(!flag[i]) pim[tol++]=i; for(int j=0; j<tol&&i*pim[j]<maxn; j++) { flag[i*pim[j]]=1; if(i%pim[j]==0) break; } } for(int i=0; i<tol; i++) //对每一个素数求各阶乘模和逆 { int k=pim[i]; mp[k]=i; p[i][0]=1, p[i][1]=1; ni[i][0]=1,ni[i][1]=1; for(int j=2; j<k; j++) //从2!到(p-1)! { p[i][j]=j*p[i][j-1]%pim[i]; ni[i][j]=-k/j*ni[i][k%j]%k; if(ni[i][j]<0) ni[i][j]+=k; } } for(int i=0; i<tol; i++) //求阶乘逆 { int k=pim[i]; for(int j=1; j<k; j++) { ni[i][j]=ni[i][j]*ni[i][j-1]%k; } }}int cal(int n,int m,int v){ if(n<m) return 0; int x=mp[v]; return p[x][n] * ni[x][m]%v * ni[x][n-m]%v;}int main(){ int n,k,p,ca=0; init(); while(scanf("%d %d %d",&n,&k,&p)==3) { if(k>n/2) k=n-k; int res=1,u_u=n-k; n++; while(n&&k) { res=res*cal(n%p,k%p,p)%p; if(res==0) break; n/=p; k/=p; } printf("Case #%d: %d\n",++ca,(res+u_u)%p); } return 0;}
- hdu 3944 DP? 组合数学与数论的结合
- HDU 3944 组合数学+数论
- HDU 4390 组合数学&数论
- HDU 4248 DP与组合数学
- hdu 4790 数论 实现 组合数学
- hdu 6143 组合数学+dp
- poj2992数论与组合数学,略水。。。
- hdu 3944 组合数学
- hdu 12310 girl friend #DP#组合数学
- hdu 5396 Expression (dp+组合数学)
- HDU 4497 GCD and LCM (数论&组合数学)
- DP?(数论+组合数学综合题:组合数性质+预处理+组合数取摸)
- poj 3252 组合数学,数论
- 数论&&组合数学_模板
- zoj 3344 //组合数学那种的DP
- poj2282(组合数学,数位上的dp)
- hdu 3811 用状态压缩DP 解决看似组合数学的题目
- hdu 3625 Examining the Rooms //组合数学DP
- 黑马程序员之IO
- lbi里的数据文件扩容(裸设备)
- 从sql数据库中读数据来创建tree
- 安卓ApiDemos学习 app/Activity/Forwarding
- 并查集
- hdu 3944 DP? 组合数学与数论的结合
- Nginx源码分析-Epoll模块
- eclipse快捷键使用大全
- 黑马程序员之GUI
- android学习之三:如何使用自定义颜色
- 第六章 - 图像变换 - 卷积和离散傅里叶变换DFT(cvDFT)
- Aforge做摄像头操作
- 友善之臂Mini2440开发板的存储系统及I/O空间总结(转)
- c语言文件操作流容易犯的错误