学习笔记:杨辉三角形上莫队(组合数莫队)(LULU胡策)

与唐林康的决战在即,面筋哥需要一件压场子的终极武器。
面筋哥手上有 M 个面筋,能量值分别为 1-M 的整数。现在面筋哥想要利用这些面筋制
作他的终极武器:Ex 面筋棒。Ex 面筋棒是一种能够发射强大剑气的能量武器。它由一些面
筋按次序连接而成。Ex 面筋棒可能会发射失败,面筋哥无法承受失败的损失。在 SPW 财团
的资助下,经过上百次的实验,面筋哥终于发现了面筋棒成功发射剑气的规律:
·面筋哥臂力有限,拿不动太长的 Ex 面筋棒,所以面筋棒的长度 L 不能大于 N,当然
它的长度不能为 0。
·每次发动攻击时,面筋棒会被触发 L 次,第 i 次触发会激活前 i 个面筋,进入蓄能状
态。
·首先剑气能量会聚集在已经激活的能量值最小的面筋上,然后能量会自发地寻找更高
的能量值,如果某一个面筋 x 的能量值是所有能量值大于当前面筋的面筋中(包括未激活的
面筋)最小的一个,那么剑气能量会转移到面筋 x 上,并提高至 s[x]。如果 x 未激活,则 Ex
面筋棒会由于能量溢出而发射失败。
·当发射能量达到当前已激活的面筋中的最大值,则第 i 次触发的能量聚集完成。
·只有当 L 次触发的能量全部完成聚集,Ex 面筋棒才能成功发射剑气。
面筋哥急切想击败唐林康,他想知道,利用他手上的面筋,能够制造出多少种不同的可
以成功发射剑气的 Ex 面筋棒。两种面筋棒不同当且仅当他们的长度不同,或某一个位置上
面筋能量不同。由于方案数太大,你只需要告诉他答案除以 19260817 的余数。
由于能量自发地提高违反了物理定律,这导致了时空的崩塌,世界线之间的隔阂被打破。
这时,你眼前突然出现了 Q 个来自各自世界的面筋哥,每个面筋哥都想知道方案总数,但
是他们拥有的面筋不一样,并且他们的臂力也不一样。你需要帮助每一个世界的面筋哥算出
方案总数。
另外面筋哥害怕自己表述不清而导致你理解出错,所以他悄咪咪地整理了一份更严谨的
表述,在早些时候放进了 ftp 里面。
【输入格式】
第一行一个正整数 Q,表示世界线的个数
接下来 Q 行,每行两个整数 M,N,表示该世界线中,面筋哥拥有 M 个面筋,能够拿动长度
至多为 N 的面筋棒。
【输出格式】
Q 行,每行一个整数,表示在该世界的条件下,能够成功发射的 Ex 面筋棒数量。
【样例输入 1】
1
4 4
【样例输出 1】
40
【样例解释】
将 Ex 面筋棒看做数列,则下列不同的组成都是能够成功发射的:
长度为 1:{1},{2},{3},{4}
长度为 2 : {1 2},{1 3},{1 4},{2 1},{2 3},{2 4},{3 1},{3 2},{3 4},{4 1},{4 2},{4 3}
长度为 3: {1 2 3},{1 2 4},{1 3 4},{2 1 3},{2 1 4},{2 3 1},{2 3 4},{2 4 1},{3 1 4},{3 2 1},{3 2 4},{3 4 1},{3
4 2},{4 2 1},{4 3 1},{4 3 2}
LULU随手组的数学题
有点毒瘤
我们发现由于题目的性质:
所以选出一些数的代价是相同的:为 C m k C_{m}^{k} Cmk
但是对于一段数它的代价是可以DP的
我们枚举当前最大的值的位置:
如果最大值在:第i号点
则后面是连续下降的。
所以代价是1
我们可以枚举前面的他实际是DP前缀和
打表出来就是 O ( 2 n ) O(2^{n}) O(2n)
然后我们现在要计算多次询问的答案:
∑ i = 1 n C m i 2 i − 1 \sum_{i=1}^{n}C_{m}^{i}2^{i-1} i=1nCmi2i1
这是实际上是组合数的前缀和
而这个实际上可以莫队!
一个东西满足莫队只需要:
向四个方向都是 O ( 1 ) O(1) O(1)转移的
设求解的东西是: S m n S_{m}^{n} Smn
n的变化是很好求解的。
S m n − 1 = S m n − C m n ∗ 2 n − 1 S_{m}^{n-1}=S_{m}^{n}-C_{m}^{n}*2^{n-1} Smn1=SmnCmn2n1
S m n + 1 = S m n + C m n + 1 ∗ 2 n S_{m}^{n+1}=S_{m}^{n}+C_{m}^{n+1}*2^{n} Smn+1=Smn+Cmn+12n
这直接是按照公式定义的
但是这实际上底也是可以同理的
观察: S m + 1 n S_{m+1}^{n} Sm+1n
它等价于: ∑ i = 1 n C m + 1 i ∗ 2 i − 1 \sum_{i=1}^{n} C_{m+1}^{i}*2^{i-1} i=1nCm+1i2i1
按照递推的转移式,可以拆解为:
∑ i = 1 n ( C m i + C m i − 1 ) ∗ 2 i − 1 \sum_{i=1}^{n}(C_{m}^{i}+C_{m}^{i-1})*2^{i-1} i=1n(Cmi+Cmi1)2i1
等价于 S m + 1 n = ∑ i = 1 n − 1 3 ∗ C m i + C m 0 ∗ 2 0 + C m n ∗ 2 n − 1 S_{m+1}^{n}=\sum_{i=1}^{n-1}3*C_{m}^{i}+C_{m}^{0}*2^{0}+C_{m}^{n}*2^{n-1} Sm+1n=i=1n13Cmi+Cm020+Cmn2n1
即: S m + 1 n = 3 ∗ S m n − C m n ∗ 2 n + C m 0 ∗ 2 0 S_{m+1}^{n}=3*S_{m}^{n}-C_{m}^{n}*2^{n}+C_{m}^{0}*2^{0} Sm+1n=3SmnCmn2n+Cm020
逆推得到: S m − 1 n = S m n + C m − 1 n − C m 0 ∗ 2 0 3 S_{m-1}^{n}=\frac{S_{m}^{n}+C_{m-1}^{n}-C_{m}^{0}*2^{0}}{3} Sm1n=3Smn+Cm1nCm020
这就是莫队了
注意块的大小的取舍。

#include
#include
#include
#include
#include
using namespace std;
inline void read(int &x){
	x=0;
	int f=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-')f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9'){
		x=x*10+ch-'0';
		ch=getchar();
	}
	x*=f;
}
typedef long long LL;
const int N=1e5+100;
const LL mod=19260817;
LL Quick_Pow(LL x,int k){
	LL ret=1;
	while(k){
		if(k&1)ret=ret*x%mod;
		x=x*x%mod;
		k/=2;
	}
	return ret;
}
//
LL powtwo[N+10];
LL fac[N+10];
LL Inv[N+10];
LL inv3;
void Pre(){
	inv3=Quick_Pow(3,mod-2);
	powtwo[0]=1;
	for(int i=1;i<=N;++i)powtwo[i]=powtwo[i-1]*2%mod;
	fac[0]=1;
	for(int i=1;i<=N;++i)fac[i]=fac[i-1]*i%mod;
	Inv[N]=Quick_Pow(fac[N],mod-2);
	for(int i=N-1;i>=0;--i)Inv[i]=Inv[i+1]*(i+1)%mod;
} 
LL C(int n,int m){	
	return fac[n]*Inv[n-m]%mod*Inv[m]%mod;	
}
//
int Belong[N];
int Sqr;
LL now=1;
int l=1;
int r=1;
inline void rplus(){
	now=((3LL*now-C(r,l)*powtwo[l]%mod+C(r,0)*powtwo[0])%mod+mod)%mod;
	++r;
}
inline void rdelete(){
	now=((now+C(r-1,l)*powtwo[l]%mod-C(r,0)*powtwo[0])%mod+mod)%mod*inv3%mod;
	--r;
}
inline void lplus(){
	now=(now+C(r,l+1)*powtwo[l]%mod)%mod;
	++l;
}
inline void ldelete(){
	now=((now-C(r,l)*powtwo[l-1]%mod)%mod+mod)%mod;
	--l;
}
struct Query{
	int l,r,Id,ans;
}Q[N];
bool cmp(Query A,Query B){
	if(Belong[A.l]^Belong[B.l])return A.lB.r;
}
bool cmp2(Query A,Query B){
	return A.Id=r){
			while(rQ[i].r)rdelete();
			while(lQ[i].l)ldelete(); 
		}
		else{
			while(lQ[i].l)ldelete();
			while(rQ[i].r)rdelete();
		}
		Q[i].ans=now;
	}
	sort(Q+1,Q+1+cnt,cmp2);
	for(int i=1;i<=cnt;++i){
		cout<

你可能感兴趣的:(组合数学,学习笔记,莫队)