Codeforces Round #131 (Div. 1) B. Numbers dp

时间:2024-07-05 22:06:26

题目链接:

http://codeforces.com/problemset/problem/213/B

B. Numbers

time limit per test 2 secondsmemory limit per test 256 megabytes
#### 问题描述
> Furik loves writing all sorts of problems, especially such that he can't solve himself. You've got one of his problems, the one Furik gave to Rubik. And Rubik asks you to solve it.
>
> There is integer n and array a, consisting of ten integers, indexed by numbers from 0 to 9. Your task is to count the number of positive integers with the following properties:
>
> the number's length does not exceed n;
> the number doesn't have leading zeroes;
> digit i (0 ≤ i ≤ 9) occurs in the number at least a[i] times.
#### 输入
> The first line contains integer n (1 ≤ n ≤ 100). The next line contains 10 integers a[0], a[1], ..., a[9] (0 ≤ a[i] ≤ 100) — elements of array a. The numbers are separated by spaces.
#### 输出
> On a single line print the remainder of dividing the answer to the problem by 1000000007 (109 + 7).
#### 样例
> **sample input**
> 3
> 1 1 0 0 0 0 0 0 0 0
>
> **sample output**
> 36

note

numbers 10, 110, 210, 120, 103 meet the requirements. There are other suitable numbers, 36 in total.

题意

给你0到9这十个数字,第i个数至少要用a[i]次,问能拼成的长度小于等于n的正整数(不能有前导零)

题解

dp[i][len]表示利用i到9的数字能拼成的长度为len的所有可能数。

状态转移方程:dp[i][len]=sigma(dp[i+1][len-k]*C[len][k])。

相当于是在用i+1到9凑成的长度为len-k的数字串里面塞进去k个i的所有可能数。用乘法原理可知去掉已经统计出来的len-k,我们要处理的就是从len里面选k个位置来放i。

注意:由于前导零不用考虑,而且只要统计正整数,所以我们在放0的时候,是不能让零放在第一位的,对于0我们可以特殊处理一下。

代码

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std; typedef __int64 LL; const int maxn = 111;
const int mod = 1e9 + 7; int dig[22],n;
LL dp[22][maxn]; LL C[maxn][maxn];
void pre() {
memset(C, 0, sizeof(C));
C[0][0] = 1;
for (int i = 1; i < maxn; i++) {
C[i][0] = 1;
for (int j = 1; j <= i; j++) {
C[i][j] = C[i - 1][j - 1] + C[i - 1][j];
C[i][j] %= mod;
}
}
} int main() {
pre();
scanf("%d", &n);
for (int i = 0; i < 10; i++) {
scanf("%d", &dig[i]);
}
memset(dp, 0, sizeof(dp));
dp[10][0] = 1;
for (int i = 9; i > 0; i--) {
for (int j = 0; j < maxn; j++) {
for (int k = dig[i]; k <=j; k++) {
dp[i][j] += dp[i + 1][j - k] * C[j][k];
dp[i][j] %= mod;
}
}
}
for (int j = 0; j < maxn; j++) {
for (int k = dig[0]; k < j; k++) {
dp[0][j] += dp[1][j - k] * C[j - 1][k];
dp[0][j] %= mod;
}
}
LL ans = 0;
for (int j = 1; j <= n; j++) {
ans += dp[0][j];
ans %= mod;
}
printf("%I64d\n", ans);
return 0;
}