数字
来源:互联网 发布:网络教育专升本难度 编辑:程序博客网 时间:2024/05/19 23:27
Description
给出一个整数n和一个数组a。数组a中包含n个整数,编号0到9。
你的任务是统计满足下列条件的正整数的个数:
1.该正整数的长度不能超过n位;
2.该正整数的最高位不能是0;
3.数字i(0<=i<=9)在该正整数中至少出现a[i]次。
Input
第一行一个整数n(1<=n<=100)。
第二行,10个空格间隔的整数,表示a[0],a[1]...a[9]里面存的数字
Output
一行,一个整数,表示满足条件的数字的个数,结果可能很大,输出与1000000007取模后的结果。
Sample Input
样例输入1:10 0 0 0 0 0 0 0 0 1样例输入2:21 1 0 0 0 0 0 0 0 0样例输入3:31 1 0 0 0 0 0 0 0 0
Sample Output
样例输入1:1样例输入2:1样例输入3:36
Hint
样例说明:
满足样例1的数字只有数字"9"
满足样例2的数字只有数字"10"
满足样例3的数字有"10,110,101,100,102,103,120,210,301,......"总共36个,这些数字都满足0出现了至少1次,1出现了至少1次,其他数字出现了至少0次,并且长度不超过3。
【分析】
一拿到这道题,感觉是搜索,因为之前做过一道类似的,但事实证明这道题搜索只能过4个点。听了老师的讲解后才知道这原来是DP。具体如下:
F[i][j]表示长度为i的由j,j+1,...,9组成的数字个数
有了这个状态数组(实在是很非主流的一种)后,方程也就不难写了。关键是要思考F[i][j]可以由哪些状态继承过来。很明显:
F[i][j]可以由F[i-k][j+1]继承(a[j]<=k<=i)。也就是说由长度为i-k的 还没出现j这个数字的 方案继承过来,即选择k个j放入数字中。那么得到DP方程:
F[i][j]=sum{F[i-k][j+1]+c[i][k]};(a[j]<=i<=N;a[j]<=k<=i;1<=j<=9;)c[i][k]表示i个中选择k个的组合。
之所以上式中的j不能等于0,是因为题目中的条件2。而在j等于0的时候的时候,只需要把组合数改为c[i-1][k]就可以了(因为最高位不能放0,所以可以有i-1个位置供选择)。
现在再来看看这道题,其实我们是用DP来思考(定状态,找继承),可是却没有决策,这就变成了递推了。在实际做题的过程中,我们常常会发现,用DP的思维来做递推题往往事半功倍,很容易找出递推公式。所以DP思维是我们需要强化和训练的。
【代码】
#include<cstdio>#include<cstdlib>#include<cstring>#include<cmath>#include<ctime>#include<iostream>#include<algorithm>using namespace std;const int MODER=1000000007;long long c[205][205];int N,a[10];long long f[205][15];void _get_c() //利用递推,预处理求出组合数组 { //c[i][j]=c[i-1][j]+c[i-1][j-1] c[0][0]=1;for(int i=1;i<=N;i++){c[i][0]=1; for(int j=1;j<=i;j++) c[i][j]=(c[i-1][j]+c[i-1][j-1])%MODER;}}void _init(){scanf("%d",&N);for(int i=0;i<=9;i++) scanf("%d",&a[i]);}void _solve(){_get_c();for(int j=9;j>=0;j--) //j逆向往前推 {if(j==9) //j==9的时候要赋初值 {for(int i=a[j];i<=N;i++) f[i][j]=1;}else if(j==0) //j==0的时候递推关系变化 { //单独讨论 for(int i=a[j];i<=N;i++) for(int k=a[j];k<=i;k++) if(i>=1) f[i][j]=(f[i][j]+f[i-k][j+1]*c[i-1][k])%MODER;} //一个细节上的问题,这里要加上花括号,不然else会悬挂到这个if上面 else {for(int i=a[j];i<=N;i++) for(int k=a[j];k<=i;k++) f[i][j]=(f[i][j]+f[i-k][j+1]*c[i][k])%MODER;}}int ans=0;for(int i=1;i<=N;i++) ans=(ans+f[i][0])%MODER; //求出答案 printf("%d\n",ans);}int main(){_init();_solve();return 0;}
- 数字
- 数字
- 数字:
- 数字
- 数字
- 数字
- 数字
- 数字
- 数字
- 数字
- 数字
- 数字
- 数字
- 【数字】--数字
- 数字数字钟课程设计
- 数字数字钟课程设计
- 数字数字钟课程设计
- 用数字造数字
- 字符串的全排列和组合算法
- C语言 5个数最值问题
- [数据结构]从中序表达式到逆序表达式(逆波兰式)(四则运算表达式求值)
- 一个KMP算法(c++版)
- 设置linux内核启动参数-挂载NFS根文件系统
- 数字
- 【五子棋AI】AI的基本结构——局面评价
- 面向对象设计的原则
- JAVA处理日期时间常用方法
- 一步步将vim改造成C/C++开发环境(IDE)
- 这些话,是乔布斯给世间留下的真正伟大礼物
- Keil MDK下如何设置非零初始化变量
- 史上最全Android开发之adb
- 基于FBX SDK的FBX模型解析与加载-(一)