Atcoder 600 11 组合数(恒等式)

题意:长度为n+1的序列a.其中[1..n]每个数都至少出现一次.
1<=n<=1e5,对每个k=[1..n] 询问长度为k的不同的子序列有多少个?


如果n个数都不同 那么长度为k的不同子序列个数为C(n,k).
序列a:[1..n]其中一个数x出现2次.其余出现一次.

[...x....x...] 两个x的位置分别为p1,p2.


长度为k中有三种情况:不包含x,有两个x,有一个x. 前两个显然没有重复的序列.
后者中的重复个数为:C(p1-1,i)*C(n+1-p2,k-1-i) [i=0..k-1].
直接计算是TLE.  因为总共选k-1个 利用组合数恒等式.

C(p1-1,i)*C(n+1-p2,k-1-i) [i=0..k-1]. =  C(p1-1 +n+1-p2 ,k-1).

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+5,mod=1e9+7;
ll n,a[N],p[N],f[N],p1,p2;
ll res[N];
ll powmod(ll x,ll n){ll s=1;for(;n;n>>=1,x=(x*x)%mod)	if(n&1)	s=(s*x)%mod;return s;}
ll C(int n,int m)
{
	if(n<m)	return 0;
	ll a=f[n],b=(f[n-m]*f[m])%mod;
	return (a*powmod(b,mod-2))%mod;
}
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	cin>>n;
	for(int i=1;i<=n+1;i++){
		cin>>a[i];
		if(!p[a[i]])
			p[a[i]]=i;
		else
		{
			p1=p[a[i]];
			p2=i;
		}
	}
	f[0]=1;
	for(ll i=1;i<N;i++)	f[i]=(f[i-1]*i)%mod;
	for(int k=1;k<=n+1;k++)
	{
		ll foo=C(p1-1+n+1-p2,k-1); 
		res[k]=(C(n+1,k)-foo+mod)%mod;
		cout<<res[k]<<'\n';
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值