链接: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
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=0;i--){
ni[i]=ni[i+1]*(i+1)%mod;
}
}
int main(){
init();
int n;
scanf("%d",&n);
for(int i=0;ip){
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;
}