現在的位置: 首頁 > 綜合 > 正文

Codeforces Round#131D

2018年01月14日 ⁄ 綜合 ⁄ 共 1581字 ⁄ 字號 評論關閉

題意:

給定數n和10個數的數組a,求滿足以下條件的數的個數
1、數的長度不超過n
2、這個數不含前導0
3、數字i至少出現a[i]次

典型的數位DP,我們設f[i][j]為前i位數使用了j-9的數字能得到的數的個數
首先枚舉長度len,對j的不同情況進行討論:
1、j=9,此時若len>=a[9],那麼f[len][9]=1否則為0
2、0<j<9,此時考慮枚舉數字j時,j+1到9已經枚舉完畢。此時j的個數可以為k(a[j]<=k<=len),
對於每個k放置在數列中的方法顯然有C(len,k)種。那麼狀態轉移方程即為f[len][j]+=f[len-k][j+1]*c[len][k]
其中c是組合數。
3、j=0,此時因為不能有前導0,所以對於0來說放置的方法只有len-1種,個數上限也是len-1,別的細節和第二種情況的是差不多的。
中間注意步步取模,注意是長度不超過n,所以最後輸出sum(f[i][0]){0<=i<=n}即可

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<string>
#include<set>
#include<queue>
#include<stack>
#include<map>
#include<cmath>
#include<cstdlib>
#define ll long long
#define maxn 100010
#define inf 1000000000
#define linf (1LL<<50)
#define hzy 1000000007
using namespace std;
inline ll read()
{
    ll x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x*=10;x+=ch-'0';ch=getchar();}
    return x*f;
}
 
inline void read(char *s,int &ts)
{
char x=getchar();
while(!(x>='a'&&x<='z'))x=getchar();
while(x>='a'&&x<='z')s[++ts]=x,x=getchar();
}
ll f[110][10];
ll c[110][110];
int n;
int a[20];
int main()
{
    scanf("%d",&n);
    for(int i=0;i<=9;i++)
    scanf("%d",&a[i]);
    for(int i=0;i<=n;i++)
    {
        c[i][0]=1;
        for(int j=1;j<=i;j++)
        c[i][j]=(c[i-1][j-1]+c[i-1][j])%hzy;
    }
    //for(int i=1;i<=n;i++)
    //for(int j=1;j<=i;j++)
    //printf("%d\n",c[i][j]);
    for(int len=0;len<=n;len++)
    {
        if(len>=a[9]) f[len][9]=1;
        else f[len][9]=0;
        for(int j=8;j>=1;j--)
        for(int k=a[j];k<=len;k++)
        f[len][j]=(f[len][j]+f[len-k][j+1]*c[len][k])%hzy;
        for(int k=a[0];k<=len-1;k++)
        f[len][0]=(f[len][0]+f[len-k][1]*c[len-1][k])%hzy;
    }
    ll ans=0;
    for(int i=0;i<=n;i++)
    ans=(ans+f[i][0])%hzy;
    printf("%I64d\n",ans);
    return 0;
}

抱歉!評論已關閉.