计数 (快速幂、逆元、组合数学隔板法)

链接:https://ac.nowcoder.com/acm/contest/1085/J
来源:牛客网
 

计数

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld

题目描述

小sun最近对计数问题来了兴趣,现在他有一个问题想问问你:

有一个含有n个数字的序列,每个数的大小是不超过1000的正整数,同时这个序列是个单调不增序列。但是很不幸的是,序列在保存过程中有些数字丢失了,请你根据上述条件,计算出有多少种不同的序列满足上述条件,答案对1000000007取模。(具体可以看样例)

输入描述:

 

第一行包含一个整数n,表示这个序列的长度。

第二行为n个整数aia_iai​,用空格隔开,如果数字是0,代表这个数字丢失了,其他的数字都在1~1000之间

输出描述:

输出一行,表示答案。

示例1

输入

复制

3
9 0 8

输出

复制

2

示例2

输入

复制

2
5 4

输出

复制

1

示例3

输入

复制

3
0 0 0

输出

复制

167167000

备注:

1≤n≤1e61\leq n \leq 1e61≤n≤1e6
0≤ai≤10000\leq a_i \leq 10000≤ai​≤1000

#include<bits/stdc++.h> 
#define ll long long
#define mod 1000000007
using namespace std;
int t;
int a[1000006];
ll A[1000006],inv[1000006];
ll quick_mi(ll x,ll y)//快速幂求逆元  inv 
{
	ll res=1;
	while(y)
	{
		if(y&1) res=res*x%mod;//!!!res取模啊!!! 
		x*=x;
		x%=mod;
		y>>=1;
	}
	return res;	
}

ll C(ll n,ll m)//组合数 
{
    ll ans=A[n]*inv[m] % mod*inv[n-m] % mod;
    return ans;
}

int main()
{
	cin>>t;
	for(int i=0;i<t;i++)
	{
		scanf("%d",&a[i]);
	}
	A[0]=1; //!!! 
	inv[0]=1;//!!! 特殊处理 
	for(int i=1;i<=1000000;i++)//阶乘预处理范围 
	{
		A[i]=A[i-1]*i%mod;//排列数  阶乘 
		inv[i]=quick_mi(A[i],mod-2);
	}
	ll ans=1;
	int num=0;
	int last=1000;
	for(int i=0;i<t;i++)
	{
		if(a[i])
		{			
			ans=ans*C(last-a[i]+num,num)%mod;
			last=a[i];
			num=0;
		}
		else num++;
	}	
	ans=ans*C(last-1+num,num)%mod;
	printf("%lld\n",ans);	
}
发布了44 篇原创文章 · 获赞 6 · 访问量 1183

猜你喜欢

转载自blog.csdn.net/qq_43868883/article/details/103568901