JSC2019-Qual F Candy Retribution gxy001

我们先把限制 $[l,r]$ 差分为 $[0,l)$ 和 $[0,r]$,这样问题转化为和不超过一个数 $u$ 的方案数。

根据插板法我们知道不考虑第二个限制的方案数为 $\sum\limits_{i=0}^u\binom{i-1+n}{n-1}=\binom{u+n}{n}$。

我们现在只需要求出不满足第二个限制的方案数 $S$ 减掉就可以了。设第 $m$ 位上的数为 $x$,枚举 $x$ 我们要求的就是有多少种序列使得 $m$ 个数 $\ge x$,$n-m$ 个数 $<x$,且至少有一个数 $=x$。至少有一个数 $=x$ 的限制是好处理的,只要求出 $m$ 个数 $\ge x+1$,$n-m$ 个数 $<x$ 的方案数减去即可。

问题转化为求解 $m$ 个数 $\ge a$,剩下的数 $< b$ 且和不超过 $u$ 的序列数,我们称其为 $f(a,b)$,由于插板法不易于处理 $<b$ 这样的限制,我们考虑钦定恰有 $i$ 个位置 $\ge b$,剩余的随意,这样的方案数就是 $\binom nm\binom{n-m}{i}\binom{u-ma-ib+n}{n}$,二项式反演可以得到,合法的方案数为 \(f(a,b)=\sum\limits_{i=0}^{n-m}(-1)^i\binom nm\binom{n-m}{i}\binom{u-ma-ib+n}{n}\) 于是有 \(S=\sum\limits_{x=1}^u(f(x,x)-f(x+1,x))\) 我们现在就获得了一个 $O(un)$ 的做法,但是我们会发现在 $f(a,b)$ 的式子中 $i$ 必须满足 $ib\le u-ma$,所以这里实际上是只有 $O(u\ln u)$ 种 $ib$ 有值的,于是我们就在 $O(u\ln u)$ 的复杂度内完成了 $S$ 的计算。

总复杂度 $O(R\log R+N)$。

#include<iostream>
using std::cin;
using std::cout;
int const mod=1e9+7;
int pow(int x,int y){
	int res=1;
	while(y){
		if(y&1) res=1ll*res*x%mod;
		x=1ll*x*x%mod,y>>=1;
	}
	return res;
}
int fac[600010],ifac[600010];
int C(int n,int m){
	return 1ll*fac[n]*ifac[m]%mod*ifac[n-m]%mod;
}
void init(int n){
	fac[0]=1;
	for(int i=1;i<=n;i++) fac[i]=1ll*i*fac[i-1]%mod;
	ifac[n]=pow(fac[n],mod-2);
	for(int i=n;i;i--) ifac[i-1]=1ll*i*ifac[i]%mod;
}
int f(int a,int b,int n,int m,int u){
	int ans=0;
	for(int i=0;i<=n-m;i++){
		long long p=u-1ll*m*a-1ll*i*b;
		if(p<0) return ans;
		ans=(ans+(i&1?mod-1ll:1ll)*C(n,m)%mod*C(n-m,i)%mod*C(p+n,n))%mod;
	}
	return ans;
}
int solve(int n,int m,int u){
	int ans=C(u+n,n);
	for(int i=1;i<=u;i++){
		ans=(ans-f(i,i,n,m,u)+mod)%mod;
		ans=(ans+f(i+1,i,n,m,u))%mod;
	}
	return ans;
}
int main(){
	std::ios::sync_with_stdio(false),cin.tie(nullptr);
	int n,m,l,r;
	cin>>n>>m>>l>>r;
	init(n+r);
	cout<<(solve(n,m,r)-solve(n,m,l-1)+mod)%mod<<'\n';
	return 0;
}