hdu5673 Robot 卡特兰数 / 默慈金数
2016-05-03 21:58
363 查看
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5673
分析:
这道题是一道裸的默慈金数,比较容易想到的是用卡特兰数来做。不了解的可以先学习一下。
卡特兰数:http://www.cnblogs.com/yaoyueduzhen/p/5456490.html
默慈金数:http://www.cnblogs.com/yaoyueduzhen/p/5456530.html
记路径长度为nn,那么机器人最多向右走⌊n/2⌋步并向左走⌊n/2⌋步。
Ans(n)=∑C(n,2i) Catalan(i)
其中 C(n,2i) 表示从n个物品中取2*i个的组合数,Catalan(n)表示第n个卡特兰数,0 <= i <= ⌊n/2⌋
基于n的取值范围,此题可以预处理出1,000,001以内的乘法逆元、卡特兰数。
每次询问,都可以递推组合数,或者提前一次性预处理好阶乘和阶乘的逆元得到组合数;累加组合数与相应卡特兰数的乘积,得到答案。
事实上,Ans(n)是第n个默慈金数,利用递推公式可以快速求出。
卡特兰数代码:
默慈金数代码:
分析:
这道题是一道裸的默慈金数,比较容易想到的是用卡特兰数来做。不了解的可以先学习一下。
卡特兰数:http://www.cnblogs.com/yaoyueduzhen/p/5456490.html
默慈金数:http://www.cnblogs.com/yaoyueduzhen/p/5456530.html
记路径长度为nn,那么机器人最多向右走⌊n/2⌋步并向左走⌊n/2⌋步。
Ans(n)=∑C(n,2i) Catalan(i)
其中 C(n,2i) 表示从n个物品中取2*i个的组合数,Catalan(n)表示第n个卡特兰数,0 <= i <= ⌊n/2⌋
基于n的取值范围,此题可以预处理出1,000,001以内的乘法逆元、卡特兰数。
每次询问,都可以递推组合数,或者提前一次性预处理好阶乘和阶乘的逆元得到组合数;累加组合数与相应卡特兰数的乘积,得到答案。
事实上,Ans(n)是第n个默慈金数,利用递推公式可以快速求出。
卡特兰数代码:
#include<iostream> #include<cstdio> #include<cmath> #include<cstring> using namespace std; const long long mod=1000000007; long long n; long long ans[1100000],ni[1100000]; long long power(long long a,long long n,long long m) { long long ans=1,tmp=a; while(n) { if(n&1) ans=ans*tmp%m; tmp=tmp*tmp%m; n=n>>1; } return ans%m; } void init() { ans[0]=1; ans[1]=1; for(long long i=1;i<=1000005;i++) ni[i]=power(i,mod-2,mod)%mod; for(long long i=2;i<=1000000;i++) ans[i]=(4*i-2)%mod*ans[i-1]%mod*ni[i+1]%mod; } int main() { init(); int T; scanf("%d",&T); while(T--) { scanf("%lld",&n); long long res=0,tmp=1; for(long long i=0;i*2<=n;i++) { res=(res+tmp*ans[i]%mod)%mod; tmp=tmp*(n-2*i)%mod*(n-2*i-1)%mod*ni[2*i+1]%mod*ni[2*i+2]%mod; } cout<<res<<endl; } return 0; }
默慈金数代码:
#include<iostream> #include<cstdio> #include<cmath> #include<cstring> using namespace std; const long long mod=1000000007; long long n; long long ans[1100000]; long long power(long long a,long long n,long long m) { long long ans=1,tmp=a; while(n) { if(n&1) ans=ans*tmp%m; tmp=tmp*tmp%m; n=n>>1; } return ans; } int main() { ans[1]=1; ans[2]=2; for(long long i=2;i<=1000000;i++) ans[i+1]=((2*i+3)%mod*ans[i]%mod+3*i*ans[i-1]%mod)%mod*power(i+3,mod-2,mod)%mod; int T; scanf("%d",&T); while(T--) { scanf("%lld",&n); cout<<ans <<endl; } return 0; }
相关文章推荐
- 安卓计算器
- 20159302《网络攻击与防范》第九周学习总结
- java笔记--理解java类加载器以及ClassLoader类
- PCL库文件配置那点事
- ubuntu终端自体重叠问题
- Problem G: 小数的处理
- 看了淘宝代销(分销)的结果
- 专题三1010
- AsyncTask(异步消息处理机制)
- classloader之getresource,findClass深度分析
- 第十周、第十一周学习总结
- 第十周、第十一周学习总结
- 【java】Commons.Configuration读取配置文件(xml/property)
- Problem F: 多个数的平均值【简单循环】
- 第9周项目3 人数不定的工资类
- DataRow 复制
- code1047 邮票面值设计
- leetcode Counting Bits
- POJ 1698 —— Alice's Chance
- Binary Tree Level Order Traversal II