牛客小白月賽17 J計數 單調不增序列方案數

鏈接:https://ac.nowcoder.com/acm/contest/1085/J
來源:牛客網

題目描述

小sun最近對計數問題來了興趣,現在他有一個問題想問問你:

有一個含有n個數字的序列,每個數的大小是不超過1000的正整數,同時這個序列是個單調不增序列。但是很不幸的是,序列在保存過程中有些數字丟失了,請你根據上述條件,計算出有多少種不同的序列滿足上述條件,答案對1000000007取模。(具體可以看樣例)

輸入描述:

第一行包含一個整數n,表示這個序列的長度。

第二行爲n個整數ai,用空格隔開,如果數字是0,代表這個數字丟失了,其他的數字都在1~1000之間

輸出描述:

輸出一行,表示答案。

示例1

輸入

3
9 0 8

輸出

2

示例2

輸入

2
5 4

輸出

1

示例3

輸入

3
0 0 0

輸出

167167000

備註:

1≤n≤1e6
0≤ai≤10000

題解:

上圖是牛客官方題解, 和我想的一樣,我dp打出表之後看出這個組合數公式 , 然後發現這個公式和盒子放球模型裏的一個公式一樣,然後發現這兩個問題等價。

一個長度爲n的序列,每個數字在1到m 之間,序列單調不增的方案數。

上述這個問題和盒子放球問題中的這個問題類似:把n個不同的球全部放到m個不同的盒子裏,盒子允許爲空的方案數。

這個問題高中就學過,隔板法,插空法。

設1到m這m個數字取的個數分別爲a1,a2....am. 那麼  a1+a2+....am=n. 並且 ai>=0

每種取法都對應一種序列。

代碼:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e6+5;
const int mod=1e9+7;
int a[maxn];
ll fac[maxn],ni[maxn];
ll ksm(ll a,ll b){
    ll ans=1;
    while(b){
        if(b&1) ans=ans*a%mod;
        b>>=1;
        a=a*a%mod;
    }
    return ans;
}
ll C(ll n,ll m){
    if(n<m||n<0||m<0) return 0;
    return fac[n]*ni[m]%mod*ni[n-m]%mod;
}
void init(){
    int n=1e6;
    fac[0]=1;
    for(int i=1;i<=n;i++) fac[i]=fac[i-1]*i%mod;
    ni[n]=ksm(fac[n],mod-2);
    for(int i=n-1;i>=0;i--){
        ni[i]=ni[i+1]*(i+1)%mod;
    }
}
int main(){
    init();
    int n;
    scanf("%d",&n);
    for(int i=0;i<n;i++){
        scanf("%d",a+i);
    }
    a[n]=1;
    ll ans=1;
    int p=1000;
    int cnt=0;
    for(int i=0;i<=n;i++){
        if(a[i]==0){
            cnt++;
        }else{
            if(a[i]>p){
                ans=0;
                break;
            }
            int m=p-a[i]+1;
            ans=ans*C(cnt+m-1,m-1)%mod;
            p=a[i];
            cnt=0;
        }
    }
    printf("%lld\n",ans);
    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章