U430605 组合数前缀和 题解

U430605 组合数前缀和 题解


题意分析

略。


思路分析

\(f_{n,m}=\sum_{i=0}^{m}\operatorname{C}_{i}^{n}\)

那么我们发现,从 \(f_{n,m}\) 其实可以方便地转移到 \(f_{n,m+1},f_{n,m-1}\),因此我们可以考虑尝试莫队,不过还要推出剩下的两个转移式:

\[\begin{aligned} f_{n,m} & = \sum_{i=0}^{m} \operatorname{C}_{i}^{n} \\ f_{n,m} & = \sum_{i=0}^{m} \operatorname{C}_{i-1}^{n-1} + \operatorname{C}_{i}^{n-1} \\ f_{n,m} & = \sum_{i=0}^{m} \operatorname{C}_{i}^{n-1} + \sum_{i=0}^{m-1} \operatorname{C}_{i}^{n-1} \\ f_{n,m} & = 2 f_{n-1,m} - \operatorname{C}_{m}^{n-1} \\ \end{aligned} \]

由此,我们推得四个转移式:

\[\begin{aligned} f_{n-1,m} & = \frac{f_{n,m}+\operatorname{C}_{m}^{n-1}}{2} \\ f_{n+1,m} & = 2f_{n,m} - \operatorname{C}_{m}^{n} \\ f_{n,m-1} & = f_{n,m} - \operatorname{C}_{m}^{n} \\ f_{n,m+1} & = f_{n,m} + \operatorname{C}_{m+1}^{n} \\ \end{aligned} \]

我们将莫队延展到数学式的参数上,就可以求得答案。

现在分析时间复杂度:假设莫队分块长度 \(S\),则块数为 \(O(\frac{n}{S})\) 级别,左指针在单块内时,右指针移动次数级别最大为 \(O(n)\),左指针单次移动次数最大为 \(O(S)\),所有单次移动都可以优化到 \(O(1)\),所以总时间复杂度为 \(O(QS+\frac{n^2}{S})\),求导后,可知块长为 \(\frac{n}{\sqrt{Q}}\) 时,最小平衡到 \(O(n\sqrt{Q})\)


CODE

#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define ll long long
#define max(a,b) ((a)<(b)?(b):(a))
#define min(a,b) ((a)>(b)?(b):(a))
#define tomax(a,b) ((a)=max((a),(b)))
#define tomin(a,b) ((a)=min((a),(b)))
#define RCL(a,b,c,d) memset((a),(b),sizeof(c)*(d))
#define FOR(i,a,b) for(register int i=(a);i<=(b);++i)
#define DOR(i,a,b) for(register int i=(a);i>=(b);--i)
#define main Main();signed main(){ios::sync_with_stdio(0);cin.tie(0);return Main();}signed Main
using namespace std;
constexpr int N=1e5+10;
namespace Modular_Arithmetic{
	#define MOD 73939133
	#define toadd(a,b) ((a)=add((a),(b)))
	#define tomul(a,b) ((a)=mul((a),(b)))
	int fac[N],inv[N];
	template<typename T1,typename T2>constexpr auto add(T1 a,T2 b){
		return a+b>=MOD?a+b-MOD:a+b<0?a+b+MOD:a+b;
	}
	template<typename T1,typename T2>constexpr auto mul(T1 a,T2 b){
		return (long long)a*b%MOD;
	}
	template<typename T,typename...Types>constexpr auto add(T a,Types... b){
		return add(a,add(b...));
	}
	template<typename T,typename...Types>constexpr auto mul(T a,Types... b){
		return mul(a,mul(b...));
	}
	int Pow(int a,int b){
		int res=1;
		for(a%=MOD;b;b>>=1,tomul(a,a))if(b&1)tomul(res,a);
		return res;
	}
	void Init(int n){
		fac[0]=1;
		FOR(i,1,n)fac[i]=mul(fac[i-1],i);
		inv[n]=Pow(fac[n],MOD-2);
		DOR(i,n,1)inv[i-1]=mul(inv[i],i);
	}
	int C(int n,int m){
		return (n<0||m<0||n<m)?0:mul(fac[n],inv[n-m],inv[m]);
	}
}using namespace Modular_Arithmetic;
int n,m,l,r,Q,Bl,Mx,sum;
int ans[N];
struct Query{
	int l,r,id,idx;
	friend bool operator <(Query a,Query b){
		return a.id^b.id?a.l<b.l:(a.r>=b.r)^(a.id&1);
	}
}qr[N];
signed main(){
	rd(Q);
	FOR(i,1,Q)rd(qr[i].r),rd(qr[i].l),tomin(qr[i].l,qr[i].r),qr[i].idx=i,tomax(Mx,qr[i].r);
	Bl=ceil(1.0*Mx/sqrt(Q)),Init(Mx);
	FOR(i,1,Q)qr[i].id=(qr[i].l-1)/Bl+1;
	sort(qr+1,qr+Q+1);
	l=0,r=1,sum=1;
	FOR(i,1,Q){
		for(;r<qr[i].r;++r)sum=add(mul(2,sum),-C(r,l));
		for(;l>qr[i].l;--l)toadd(sum,-C(r,l));
		for(;r>qr[i].r;--r)sum=mul(add(sum,C(r-1,l)),inv[2]);
		for(;l<qr[i].l;++l)toadd(sum,C(r,l+1));
		ans[qr[i].idx]=sum;
	}
	FOR(i,1,Q)wr(ans[i]);
	return 0;
}

posted @ 2024-05-10 19:34  Add_Catalyst  阅读(32)  评论(0)    收藏  举报