【牛客小白月赛17】J - 计数【数论,数学】

题目大意:

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


思路:

首先题目要求一个单调不增序列,套路性的把位置 i i i上的数字加上 n − i + 1 n-i+1 ni+1。这样就转变成了一个单调递减序列。
那么对于位置 i , j i,j i,j的两个已知数字,如果 ( i , j ) (i,j) (i,j)中全部是未知数字,那么显然我们就需要在¥ a [ i ] , a [ i + 1 ] . . . a [ j − 1 ] , a [ j ] a[i],a[i+1]...a[j-1],a[j] a[i],a[i+1]...a[j1],a[j] a [ i ] − a [ j ] − 1 a[i]-a[j]-1 a[i]a[j]1个数字中选出 j − i − 1 j-i-1 ji1个数字,满足这些数字排序后单调递减。
显然这就是 C a [ i ] − a [ j ] − 1 j − i − 1 C_{a[i]-a[j]-1}^{j-i-1} Ca[i]a[j]1ji1。因为组合是满足互不相同的。
为了方便,就在 a a a中加入 n , 0 n,0 n,0两个元素,注意 n n n 0 0 0都是要加上 n − i + 1 n-i+1 ni+1的。


代码:

#include <cstdio>
using namespace std;
typedef long long ll;

const int N=1000010,MOD=1000000007;
ll a[N],last,f[N*2],ans;
int n;

ll power(ll x,ll k)
{
	ll s=1;
	for (;k;k>>=1,x=x*x%MOD)
		if (k&1) s=s*x%MOD;
	return s;
}

ll C(ll x,ll y)
{
	if (x<y) return 0;
	ll inv=power(f[y]*f[x-y]%MOD,MOD-2);
	return f[x]*inv%MOD;
}

int main()
{
	f[0]=1;
	for (int i=1;i<=N+2000;i++)
		f[i]=f[i-1]*i%MOD;
	scanf("%d",&n); n+=2;
	a[1]=1000+n;
	for (int i=2;i<n;i++)
	{
		scanf("%d",&a[i]);
		if (a[i]) a[i]+=(n-i+1);
	}
	a[n]=2;
	ans=1;
	for (int i=1;i<=n;i++)
		if (a[i])
		{
			if (last) ans=ans*C(a[last]-a[i]-1,i-last-1)%MOD;
			last=i;
		}
	printf("%lld",ans);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值