【题】【数位动规】NKOJ1725 数字

来源:互联网 发布:上海java培训周日班 编辑:程序博客网 时间:2024/05/21 11:17

NKOJ1725 数字
时间限制 : 20000 MS 空间限制 : 128000 KB

问题描述
给出一个整数n和一个数组a。数组a中包含十个整数,编号0到9。
你的任务是统计满足下列条件的正整数的个数:
1.该正整数的长度不能超过n位;
2.该正整数的最高位不能是0;
3.数字i(0<=i<=9)在该正整数中至少出现a[i]次。

输入格式
第一行一个整数n(1<=n<=100)。
第二行,10个空格间隔的整数,表示a[0],a[1]…a[9]里面存的数字

输出格式
一行,一个整数,表示满足条件的数字的个数,结果可能很大,输出与1000000007取模后的结果。

样例输入
样例输入1:
1
0 0 0 0 0 0 0 0 0 1
样例输入2:
2
1 1 0 0 0 0 0 0 0 0
样例输入3:
3
1 1 0 0 0 0 0 0 0 0

样例输出
样例输入1:
1
样例输入2:
1
样例输入3:
36

提示
样例说明:
满足样例1的数字只有数字”9”
满足样例2的数字只有数字”10”
满足样例3的数字有”10,110,101,100,102,103,120,210,301,……”总共36个,这些数字都满足0出现了至少1次,1出现了至少1次,其他数字出现了至少0次,并且长度不超过3。

注:此题可能会用到排列组合的知识!
组合公式:Cnk=n!/((n-k)!*k!)=Cn-1k+Cn-1k-1
排列公式:Ank=n!/(n-k)!=k!*Cnk
Cn0=An0=1

来源 源自codeforce

思路:
状态:f[i][j]表示用 j~9的数字填i个位置的总方案数。
方程:
j==9时,f[i][j]=1(i>=a[9]) / f[i][j]=0(i< a[9])

j==1~8时,f[i][j]=sum{ c[i][k]*f[i-k][j+1]} (a[j]<=i<=n, a[j]<=k<=i)
//先考虑填j的情况,可以填c[i][k]种,然后再考虑用j+1~9填满i-k个格子的情况:f[i-k][j+1], 乘起来。

j==0时,f[i][j]=sum{ c[i-1][k]*f[i-k][j+1]} (a[j]<=i<=n, a[j]<=k<=i)
//大致同上,但0不能填最高位,所以填c[i-1][k]种

#include<cstdio>#include<iostream>using namespace std;const long long mod=1000000007;long long c[103][111],f[103][110];long long a[10];int main(){    int n;scanf("%d",&n);    for(int  i=0;i<=9;i++) scanf("%I64d",a+i);    for(int i=0;i<=n;i++)c[i][0]=1;    for(int i=1,j;i<=n;i++)     for(j=1;j<=i;j++)      c[i][j]=(c[i-1][j]+c[i-1][j-1])%mod;    for(int i=a[9];i<=n;i++) f[i][9]=1;    for(int j=8,k,i;j>=0;j--)    {        for(i=a[j];i<=n;i++)        {            if(j!=0) for(k=a[j];k<=i;k++) f[i][j]=(f[i][j]+(c[i][k]*f[i-k][j+1])%mod)%mod;            else for(k=a[j];k<i;k++) f[i][0]=(f[i][0]+(c[i-1][k]*f[i-k][1])%mod)%mod;        }    }    long long ans=0;    for(int i=a[0];i<=n;i++)     {        ans=(ans+f[i][0])%mod;     }    printf("%I64d",ans);}
0 0
原创粉丝点击