bzoj 4403: 序列统计【lucas+组合数学】

首先,给一个单调不降序列的第i位+i,这样就变成了单调上升序列,设原来数据范围是(l,r),改过之后变成了(l+1,r+n)
在m个数里选长为n的一个单调上升序列的方案数为\( C_m^n \),也就是随便选n个数只能组成惟一的单调上升序列,所以要求的式子就变成了

\[\sum_{i=1}^{n}C_{r-l+i}^{i} \]

这样看着比较难受,我们把它改成

\[\sum_{i=1}^{n}C_{r-l+i}^{r-l} \]

我们在开头加一个\( C_{r-l+1}^{r-l+1} \),这样根据\( C_nm=C_{n-1}m+C_{n-1}^{m-1} \),他就可以和式子的第一项\( C_{r-l+1}^{r-l} \)合并为\( C_{r-l+2}^{r-l+1} \),然后这个又可以可第二个合并,以此类推,最后这个式子就会合并为\( C_{r-l+n+1}^{r-l+1} \),然后再减掉\( C_{r-l+1}^{r-l+1}=1 \)即可
然后用lucas求这个组合数即可

#include<iostream>
#include<cstdio>
using namespace std;
const long long N=1000010,mod=1e6+3;
long long T,n,l,r,fac[N],inv[N];
long long ksm(long long a,long long b)
{
	long long r=1;
	while(b)
	{
		if(b&1)
			r=r*a%mod;
		a=a*a%mod;
		b>>=1;
	}
	return r;
}
long long C(long long n,long long m)
{
	if(m>n)
		return 0;
	return fac[n]*inv[m]%mod*inv[n-m]%mod;
}
long long lucas(long long n,long long m)
{
	if(m>n)
		return 0;
	return n<mod?C(n,m):lucas(n/mod,m/mod)*C(n%mod,m%mod)%mod;
}
int main()
{
	scanf("%lld",&T);
	fac[0]=1,inv[0]=1;
	for(int i=1;i<mod;i++)
		fac[i]=fac[i-1]*i%mod;
	inv[mod-1]=ksm(fac[mod-1],mod-2);
	for(int i=mod-2;i>=1;i--)
		inv[i]=inv[i+1]*(i+1)%mod;
	while(T--)
	{
		scanf("%lld%lld%lld",&n,&l,&r);
		printf("%lld\n",(lucas(r-l+n+1,r-l+1)-1+mod)%mod);
	}
	return 0;
}
posted @ 2018-10-17 20:35  lokiii  阅读(175)  评论(0编辑  收藏  举报