题解 【BZOJ 4403】序列统计

【题意】

给定三个正整数 \(N\)\(L\)\(R\),统计长度在 \(1\)\(N\) 之间,元素大小都在 \(L\)\(R\) 之间的单调不降序列的数量。

输出答案对 \(10^6\!+\!3\) 取模的结果。

【样例输入】

2
1 4 5
2 4 5

【样例输出】

2
5

【题解】

首先,非常巧妙的

在求单调不降区间时,我们可以将第 \(i\) 位上的数 \(+i\)

将其转换为求单调上升序列,权值范围变成了 \([l+1,r+n]\),一共有 \(n+r-l\) 个数,求取出 \(n\) 个数有多少方案

如果选 \(i\) 个数,它可以取的数的个数就是 \(C^{i}_{r-l+i}\)

\(M=r-l+1\)

所以我们要求所有长度的方案数就是

\[\begin{align}&\ \ \ \!\ \ \sum\limits^{n}_{i=1}C^i_{M+i-1}\\&=\sum\limits^{n}_{i=1}C^{M-1}_{M+i-1}\\&=\sum\limits^{n}_{i=1}C^{M-1}_{M+i-1}+C^{M}_{M}-1\\&=\sum\limits^{n}_{i=2}C^{M-1}_{M+i-1}+C^{M-1}_{M}+C^{M}_{M}-1\\&=\sum\limits^{n}_{i=2}C^{M-1}_{M+i-1}+C^{M}_{M+1}-1\\&=\sum\limits^{n}_{i=3}C^{M-1}_{M+i-1}+C^{M}_{M+2}-1\\&=C^{M}_{M+n}-1\\&=C^{r-l+1}_{n+r-l+1}-1\end{align} \]

然后,由于 \(n\) 较大,我们用 Lucas 定理求组合数就好了,awa

代码如下:

#include<bits/stdc++.h>
#define rint register int
using namespace std;
inline int read(){
	int s=0,f=1;char c=getchar();
	while(c<'0'||c>'9'){if(c=='-')f=0;c=getchar();}
	while(c>='0'&&c<='9')s=(s<<1)+(s<<3)+c-48,c=getchar();
	return f?s:-s;
}
const int Mod=1e6+3;
int power(int a,int b){
	int res=1;
	while(b){
		if(b&1) res=1ll*res*a%Mod;
		a=1ll*a*a%Mod; b>>=1;
	}
	return res%Mod;
}
int n,l,r;
int fac[1000010],inv[1000010];
int C(int n,int m){
	if(m>n) return 0;
	return 1ll*fac[n]*inv[n-m]%Mod*inv[m]%Mod;
}
int Lucas(int n,int m){
	if(n<m) return 0;
	if(m==0) return 1;
	if(n<Mod&&m<Mod) return C(n,m);
	return 1LL*Lucas(n/Mod,m/Mod)*C(n%Mod,m%Mod)%Mod;
}
int main(){
	freopen("seq.in","r",stdin);
	freopen("seq.out","w",stdout);
	fac[1]=1; inv[0]=fac[0]=1;
	for(rint i=2;i<Mod;++i) fac[i]=1ll*fac[i-1]*i%Mod;
	inv[Mod-1]=power(fac[Mod-1],Mod-2);
	for(rint i=Mod-1;i>1;--i) inv[i-1]=1ll*inv[i]*i%Mod;
	int T=read();
	while(T--){
		n=read(); l=read(); r=read();
		printf("%d\n",(Lucas(n+r-l+1,n)-1+Mod)%Mod);
	}
	return 0;
}
原文地址:https://www.cnblogs.com/LCGUO/p/12445277.html