计数dp

错位排列计数 (组合意义dp)

题目

给定长度为 n 的排列,求解其错位排列数

题解

Dn 表示长度为 n 的排列的错排数,考虑我们已经知道了前 n1 个错排数,那么对新加入的这第 n 个数进行分类讨论

  • 直接与前面的数交换,有 (n1)×Dn2 种方案
  • 放在前面某个数的位置上,那么相当于给原来 n1 个数做了错排,有 (n1)×Dn1 中方案
    所以

Dn=(n1)×(Dn1+Dn2)

这个递推式可以求出其通项,但这不是本博客讨论的范围,读者感兴趣的自行了解即可

NOIP 四校联测 Day1 T2 (组合意义dp)

题目

给定两个排列 A,B,求字典序介于 A,B 之间的排列最大前缀个数恰好为 k 的排列的个数

|A|,|B|3000

题解

首先我们考虑没有字典序的限制要怎么做,设 f[i][j] 表示倒着往前考虑到第 i 个数,最大前缀个数为 j 时的排列的个数,转移时考虑组合意义

f[i][j]=f[i1][j1]+(i1)×f[i1][j]

也就是我们当前的 i 是最小的那个数,我们考虑它如果放在最前面,那么前缀最大值的个数会 +1,否则不会发生改变

考虑正解

一眼丁真,类似数位dp,应该是要进行一个差分的,也就是 a数的个数b数的个数

于是我们考虑从前到后枚举每一位,以 a数的个数 为例,假设 i 位之前都是相同的,我们枚举每一个在 A 数组的前 i1 个位置没有出现过,而且比 a[i] 大的数字 B 填到位置 i
因此前 i 个位置我们已经填好了,且消除了对后面字典序的限制

考虑 1n 中没有在前 i 个位置出现过的数字的集合为 S ,设我们已经填了的数字的最大值为 mx ,则 S 集合中所有小于 mx 的数字,都不会对前缀最大值的个数产生贡献

设前 i 个位置中,前缀最大值的个数为 CS 集合中大于 mx 的数字个数为 D,那么有我们在 i+1n 必须整出 kC 个前缀最大值才可以

S 集合中小于 mx 的数是可以随便填的,所以当前对答案的贡献就是

(DkC)×f[D][kC]×(niD)!

然后把所有 i 对应的答案加起来就行了,时间复杂度 O(nk)

NOIP 四校联测 Day2 构造数组 (辨认无意义的状压dp+组合意义dp)

题目

你现在有一个长度为 n 的数组 a。一开始,所有 ai 均为 0。给出一个同样长度为 n 的目标数组 b。求有多少种方案,使得通过若干次以下操作,可以让 a 数组变成 b

  • 选出两个不同的下标 1i<jn,并将 aiaj 同时增加 1

两种方案被称之为不同的,当且仅当存在一个 x 使得一种方案中第 x 次操作选择的两个下标 (i,j) 与另一种方案中的不同。

1n5 0001bi30 000bi30 000

题解

这道题感觉出的挺好的,部分分给的挺多的,正解是不太好想的,考场上花了好长时间想,最后也没调出来

首先我们可以将这个问题转化成,我现在有 n2 个容量为 2 的桶,然后我要往这些桶里面放东西。

一种朴素的状压dp做法是,考虑设 f[i][s] 表示考虑到第 i 个元素,各个桶的放置情况是 s 时的方案数。

然而我们发现我们其实并不关心每个桶放数的情况,我们只关心放了 0 个,1 个,2 个桶的数的个数,因此我们可以将状态设为 f[i][j][k] 表示考虑到第 i 个元素,个数为 1 的桶有 j 个,个数为 2 的桶有 k 个时的方案数,这样可以推出个数为 0 的桶的个数,转移时枚举当前元素有多少分给了 0 ,多少分给了 1 ,组合数计算转移即可

更进一步,我们发现知道了个数为 2 的桶的数量,我们是可以计算出考虑到第 i 个元素时个数为 1 的桶的数量的(因为前面的桶一定要全选完,不然没法跟后面的桶配对),转移同上

时间复杂度 O((bi)2)

容斥原理套路于DP

容斥原理在dp中有如下的经典应用:

  1. 一个也没有=所有情况至少一个+至少两个+
  2. 所有限制=没有限制一个限制+两个限制
  3. 恰好有k=至少有k(k+1k)至少有k+1+(k+2k)至少有k+2
  4. min-max容斥 max(s)=ts(1)|t|1min(t)

一般容斥原理直接暴力做的复杂度是 O(n2n),需要我们用dp或者多项式进行优化

P5664 [CSP-S2019] Emiya 家今天的饭 (容斥原理套路1)

题目

题解

首先,如果直接考虑本题合法的方案数,我们发现题目中的限制有些过于多了,正难则反,考虑容斥

所以我们可以钦定一定有某一种食材超过了限制,那么答案就是总的方案数减去不合法的方案数。设 f[i][j][k] 表示考虑到第 i 种烹饪方法,超限食材使用了 j 次,其它食材使用了 k 次的方案数; sum 表示第 i 种烹饪方式所能做的菜的种类的和。那么枚举当前考虑的食材是 c ,那么有转移

f[i][j][k]=f[i1][j][k]+f[i1][j1][k]×a[i][c]+f[i1][j][k1]×(sum[i]a[i][c])

不合法的方案数就是

j>kf[i][j][k]

g[i][j] 表示考虑到第 i 种烹饪方式,使用了 j 种食材时的总方案数,转移为

g[i][j]=g[i1][j]+sum[i]×g[i1][j1]

于是

i=1kg[n][i]

就是我们的总方案数

综合来看,我们目前的时间复杂度是 O(n3m) 的,无法通过本题,于是考虑优化

这就是这道题最经典的地方了,我们发现对于 j,k 这两维,我们最后统计答案的时候关心的仅仅只是它们的相对大小关系,因此我们更改状态为 f[i][j] 表示考虑到第 i 种烹饪方式,钦定的使用数量最多的那一种食材相对其它食材的总和的差为 j,那么转移就变成了

f[i][j]=f[i1][j]+f[i][j1]×a[i][c]+f[i1][j+1]×(sum[i]a[i][c])

于是时间复杂度就降为了 O(n2m)

P1450 [HAOI2008] 硬币购物 (容斥原理套路1)

题目

共有 4 种硬币。面值分别为 c1,c2,c3,c4

某人去商店买东西,去了 n 次,对于每次购买,他带了 dii 种硬币,想购买 s 的价值的东西。请问每次有多少种付款方法。

1ci,di,s1051n1000

题解

与上一道题同理,直接利用分组背包计算合法的方案数肯定是T飞了的,所以同样考虑容斥

我们分别钦定有 1 种, 2 种, 3 种 ,4 种硬币超过了限定了数量,没有限定的硬币随便选,假设当前选择的超限硬币组成的集合为 S 那么我们每次就相当于做一个背包容量为 siS(di+1)×ci 的完全背包,容斥一下,奇加偶减即可,这个时间复杂度就降为了 O(n) ,采用预处理完全背包的做法的话带一个 4 的常数,不预处理也是可以通过的

BZOJ3622 已经没什么好害怕的了 (容斥原理套路3)

题目

给定 a,b 两个长度均为 n 的数列,我们现在要对它们进行两两配对,问配对后 ab 大的个数比 ba 大的个数多 k 组的方案数

n5000

题解

无序的序列过于丑陋,所以我们先要对两个序列先进行一个排序

p[i] 表示使得 b[j]<a[i] 最大的 j

同样与上一题类似,设 f[i][j] 表示考虑到 a 序列的第 i 位,已有 ja>b 的方案数,剩下的随意分配,即对于所有的 f[n][i] 都要乘上一个 (ni)!

我们想要的就是 a>b d的组数恰好为 nk2 的方案数

我们现在对 f[n][i]i>nk2 的部分进行一个容斥,令 m=nk2 ,那么就有

ans=i=mn(1)im(iim)f[n][i]

时间复杂度 O(n2)

HDU 4336 Card Collector (容斥原理套路4 min-max容斥)

题目

n 张卡牌,每次拆开一包方便面有 pi 的概率得到第 i 张卡牌,保证 p1+p2++pn1 , 所以方便面里可能存在没有牌的情况,求收集完 n 张卡牌,需要拆开的方便面包数的期望

题解

min-max容斥 常用于解决形如“全部出现的期望时间”问题,处理方法如下:

ti 为第 i 个物品出现的时间, min(S) 表示集合 S 中的物品至少一个出现的期望时间,max(S) 表示集合 S 中的物品全部出现的期望时间

又因为单位时间内 S 中出现至少一个的概率为 p,那么在 S 中出现至少一个的期望时间就是 1p

所以,对于本题,

min(S)=1iSpi

我们套用 min-max容斥 的公式就可以过掉这道题了

时间复杂度 O(2n)

ARC101E Ribbons on Tree (容斥原理套路2)

题目

给定一个 n 个点的树,n 为偶数,点与点之间两两配对,配对点之间的边被覆盖,问有多少种配对方式,使得每一条边都有被覆盖

n5000

题解

直接计算是 O(n3) 的,无法通过本题

所以考虑容斥,设 S 表示没有被覆盖的边的集合,将这些视作断掉的边,那么就有

ans=SE(1)|S|f(S)

其中 f(S) 表示不能覆盖到 S 中边的方案数,那么答案就是

ans=SE(1)|S|f(S)

g(n) 表示 n 个点任意配对的方案数,那么有 g(n)=n!! (双阶乘)

dp[u][x] 表示结点 u 所在联通块大小为 x 时的方案数,注意此时 u 所在的联通块并没有独立出来,没有算在联通块总数中

对于 x1 的情况,转移就是树上背包,复杂度证明与"BZOJ 4033 树上染色"是一样的

对于 dp[u][0] 的情况,此时我们就将当前点 u 所在的联通块独立出来,也就是钦定了 u 到其父亲的这条边被删掉了,我们有 dp[u][0]=x=1sizudp[u][x]×g[x] 因为此时被删掉的边集大小大了 1

时间复杂度 O(n2)

BZOJ 4767 两双手 (容斥原理套路2)

题目

棋盘上 (0,0) 处有一个棋子。棋子只有两种走法,分别对应向量 (Ax,Ay),(Bx,By)。同时棋盘上有 n 个障碍点 (xi,yi),棋子在任何时刻都不能跳到障碍点。
求棋子从 (0,0) 跳到 (Ex,Ey) 的方案数。答案对 109+7 取模

Ex,Ey,n5000,保证 (Ax,Ay)(Bx,By) 不共线

题解

因为两个向量不共线,由平面向量基本定理,加之旗子只有两种走法,我们可以找到对于一个变换后坐标为 (x1,y1) 的点 A 和坐标为 (x2,y2) 的点 B,那么从前者走到后者的方案数就是 (x2x1+y2y1x2x1),记这个方案数为 cnt[A][B]

接着我们考虑容斥原理的套路 2,设 f[i] 表示 i障碍之前不经过任何障碍到达障碍 i 的方案数,转移有

f[i]=cnt[i][0]j=1i1f[j]×cnt[j][i]

时间复杂度是 O(n2)

ZR2022 NOIP十连测 Day5 T3 (数位dp+容斥原理套路1)

题目

小K想知道你可不可以帮他验算。

小K有 k 个在 [0,x] 范围内的随机整数 a1,,ak,记 f(x) 表示 x 的所有非零数位的积,例如 f(0)=1,f(1145141919810)=1×1×4×5×1×4×1×9×1×9×8×1f(0)=1,f(1145141919810)=1×1×4×5×1×4×1×9×1×9×8×1。现在小 k 想知道 f(i=1kai) 的期望值。

小K已经用超级计算机计算出了精确值,所以你只需要算出答案乘上 (x+1)k109+7 取模的值帮他验算就好了

k20,n10104

题解

毒瘤题!

乍一看就很像一个数位dp,但这道题困难的地方在于如何求出每一个 f(n) 它的系数是多少,并且如何将这个系数分离出来变成数位dp可做的东西

然后难的就是这一部分,所以我把这题归到了计数dp中(尽管它看着更像是一个数位dp)

我们设 g(n) 表示使得 i=1kai=n 的方案数,那么考虑容斥,有

g(n)=i=0k(1)i(ki)(n(x+1)i+k1k1)

组合意义就是对大于 x+1 的数的个数进行容斥,后面那一部分考虑整体加一后插板

于是我们要求的答案就变成了

i=0kxf(i)g(i)=i=0kxf(i)j=0k(1)j(kj)(i(x+1)j+k1k1)=j=0k(1)j(kj)i=0kx(i(x+1)j+k1k1)f(i)=j=0k(1)j(kj)l=0k1cj,li=0kxf(i)il

其中

cj,l=[il](i(x+1)j+k1k1)

这个东西显然是可以 O(k4) 暴力做的

这样我们的问题就转化为求

i=0kxf(i)il

我们参考以往数位dp的经验,对上面那个式子进行转移,设 dp[j]=i=0kxf(i)ij ,假设我们枚举当前位 now 的取值为 x ,加完上一位时得到的数位 num 那么有转移

dp[a+b]f(num+x×10now)×(num+x×10now)a+b

即从

f(num+x×10now)×(num+x×10now)a+b=(a+ba)×f(x)×f(num)×numb×(x×10now)a=(a+ba)×f(x)×dp[b]×(x×10now)a

转移而来
最后注意 (nm),(n<m) 时是 0 ,而我们在算系数的时候会把这玩意算负,所以最后那个式子改成

j=0k(1)j(kj)l=0k1cj,li=j(x+1)kxf(i)il

时间复杂度 O(k4+k3lgx)

[SRM 697] ConnectedStates (prufer序列计数)

题目

n个城市,每个城市有个权值wi,任意两个城市i,j之间的道路数有wi×wj条。对于每种生成树,若每个点的度数为di,则贡献为 di。求所有无根生成树的权值和。

n1000

题解

吐槽:真毒瘤

这是一个有标号无根树问题,所以我们可以考虑搞出它的prufer序列,每个点的个数就是prufer序列中出现的次数+1

对于一个固定的prufer序列(无根树),方案总数显然是widi

贡献就再乘上度数之积为diwidi

然后我们再算有多少种prufer序列,每个数都有一个出现次数的全排列显然是多重组合数,所以方案数有

(n2)!(di1)!

因此我们最终所要求的东西就是

di=2n2(n2)!(di1)!diwidi=(n2)!di=2n2diwidi(di1)!

f[i][j]表示考虑到第i个数,度数和为j的方案数,枚举当前位的度数k,转移就乘上一个kwik(k1)!,这部分可以预处理出来

所以暴力转移的复杂度是O(n3)

考虑使用多项式的幂公式,即

(x1++xt)n=ti=n(nt1,t2,tn)xiti

我们令ai=di1,那么有

原式=(n2)!ai=n2(0a1,a2,,an)(ai+1)!wiai+1=(n2)!wiai=n2(0a1,a2,,an)(ai+1)!wiai

现在我们离化简只差(ai+1)这个东西了,考虑它实际上是在枚举子集(枚举a1an几个相互组成的单项式),我们考虑当前我们枚举到的单项式是a2a3a7,那么这个单项式对答案的贡献为(注意单项式被乘进了分母里,所以对应的加和也要减3),前面(n2)!wi就先不管了

w2w3w71(n5)!ai=n5(n5a1,a21,a31,,an)wiai=w2w3w71(n5)!(w1++wn)n5

所以类比到整个式子就变成了

(n2)!wik=0n2(n2kwi)(w1+wk)n2k(n2k)!

f[t][k] 表示只考虑使用前 t 个数组合,所有 k 项式之和是多少。
转移就是 f[t][k]=f[t1][k]+f[t1][k1]×wt
那么这道题就可以 O(n2)

ZR2023 NOIP赛前20连测 Day1 T3 (组合意义转多项式优化dp)

[题意](【noip赛前20天冲刺集训 day1】迷路 - 题目 - Zhengrui Online Judge (zhengruioi.com))

题解

题目的意思可以简化成,从每个起点出发,根据是否碰到树可以记作 0/1 ,这样每条路径就是一个 01 串,题目要求的就是这 r01 串两两不同的期望步数,起点一共有 (n×mr) 种选法,考虑统计方案数

从第一步到第 n×m 步依次考虑,我们将无法区分的起点集合放在一个等价类中,那么这个过程可以视作等价类的分裂,由于有树的地方有限(记所有 01$ 中有树的位置个数为 T),所以我们可以在每个有树的地方,将所有有树的 01 串,从其所在的等价类中分离出来,这个过程可以用 hash 动态维护,时间复杂度 O(nmT)

考虑 dp ,设 f[i][j] 表示考虑到第 i 个等价类,选了 j 个集合,使得它们处于不同等价类中的方案数,这样计算的时间复杂度是 O(n2m2r2) ,非常不优

于是这里开始上多项式了,我们设当前等价类的大小分别为 a1,a2,,ak ,方案数即为 [xr]i=1k(1+aix) ,每一次把一个大小为 a 的等价类分裂为 bc (这里 a,b,c 的大小通过前面的 hash 求出)就是给这个多项式除一个 a+1 并乘上 (b+1)×(c+1) ,由于我们只需要知道这个多项式的前 r 项,所以这里单次转移的时间复杂度是 O(r) 的,整个 dp 的时间复杂度就为 O(nmr)

这样总时间复杂度即为 O(nmk+nmr)

ZR2023 NOIP赛前20连测 Day6 T3 (插板法+底数较小组合数的处理方法)

题意

你当前想要做一个有关概率的问题。

具体的,有 n 个随机变量,每个随机变量以相同的概率分布在 [0,9]

当前你需要计算有多少概率使得变量的和小于等于为 k

当然你并不满足于此,你尝试将这 n 个变量顺序排成一个十进制数(第 1 个变量是最高位,第 n 个变量是个位)。

要求这个十进制数大小 modp=0

你需要对 k=0m 都求出来结果。

为了方便,你只需要输出满足条件的概率乘上 10n

由于答案可能很大,你只需要输出答案在 mod998244353 意义下的结果。

对于所有测试点满足 1n109,1p50,1m1000

题解

首先,你仔细想一下我们上面提到的常规数位dp做法,会发现它很困难,出题人的意思是可以用多项式做,挺抽象的

所以我们考虑另一种做法,我们将所有的 k ,按照 10kmodp 的值分成若干剩余类,然后考虑 dp,设 fi,j,k 表示考虑到第 i 个剩余类,当前数位和为 j ,当前数模 p 的结果是 k 时的方案数。我们记 gi,j 表示第 i 个剩余类对数位和产生 j 的贡献的方案数。设当前我们要给数位和加 d ,那么转移方程即为

fi+1,j+d,(k+i×d)modpfi,j,k×gi,d

考虑如何求出 gi,j ,首先通过找 10kp 的循环节,我们很容易算出来每个剩余类的大小为多少,记作 cnti ,考虑我们现在的贡献 j 都是由剩余类 i 的哪些位置组成的,这里可以插板法算,也就是把 cnti 个板插到 j 个位置上,板 k 和板 k+1 之间的数的个数就是第 k 个位置所产生的贡献大小,这里的方案数即为。

(cnti+j1j)

注意到一个位置的贡献最高是 9 ,所以我们考虑容斥,钦定一些位置的贡献至少是 10 ,钦定了 k 个位置,系数就是 (1)k(cntik) ,然后还要把 j 减去 10k

然后由于 cntin 同阶,所以我们算上面的组合数需要用到下降幂,即

(nm)=nmm!

总时间复杂度即为 O(m2p2)

带注释代码:

#include<bits/stdc++.h>
using namespace std;
#define int long long
inline int read()
{
	int x=0,f=1;char ch=getchar();
	for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-1;
	for(;isdigit(ch);ch=getchar()) x=(x<<1)+(x<<3)+(ch^48);
	return x*f;
}
const int mod=998244353,M=1010,P=51;
int up[M],dw[M],fac[M],ifac[M];
int n,p,m,N;
inline int ksm(int a,int b)
{
	int val=1;
	while(b)
	{
		if(b&1) val=val*a%mod;
		a=a*a%mod;
		b>>=1;
	}
	return val;
}
inline void init(int n)
{
	N=n;
	dw[0]=1;
	for(int i=1;i<M;++i) dw[i]=dw[i-1]*(n-i+1)%mod;
	up[0]=1;
	for(int i=1;i<M;++i) up[i]=up[i-1]*(n+i-1)%mod;
}
inline int Cd(int x)
{
	if(x>N) return 0;
	return dw[x]*ifac[x]%mod;
}
inline int Cu(int x)
{
	return up[x]*ifac[x]%mod;
}
int ok[M],id[M],val[M],cnt[M];
int g[P][M];
int f[P][M][P];
signed main()
{
	n=read();p=read();m=read();
	fac[0]=1;
	for(int i=1;i<M;++i) fac[i]=fac[i-1]*i%mod;
	ifac[M-1]=ksm(fac[M-1],mod-2);
	for(int i=M-2;i>=0;--i) ifac[i]=ifac[i+1]*(i+1)%mod;
	int u=1,tot=0,L=0,R=-1;
	for(int i=1;i<=n;++i)//找模p意义下的循环节,用来计算各个剩余类的大小
	{
		u%=p;
		if(ok[u])
		{
			L=id[u];R=i-1;
			break;
		}
		++cnt[u];
		id[u]=++tot;
		val[tot]=u;
		ok[u]=1;
		u*=10;u%=p;
	}
	if(R!=-1)
	{
		int k=(n-R)/(R-L+1);
		for(int i=L;i<=R;++i) cnt[val[i]]+=k;
		u=val[R]*10%p;
		for(int i=R+k*(R-L+1)+1;i<=n;++i)
		{
			u%=p;
			++cnt[u];
			id[u]=++tot;
			val[tot]=u;
			ok[u]=1;
			u*=10;u%=p;
		}
	}
	for(int i=0;i<p;++i)
	{
		init(cnt[i]);
		for(int j=0;j<=m;++j)
		{
			int res=0;
			for(int k=0;;++k)
			{
				if(j<10*k) break;
				if(k&1) res+=(mod-1)*Cd(k)%mod*Cu(j-10*k)%mod;
				else res+=Cd(k)*Cu(j-10*k)%mod;
			}
			g[i][j]=res%mod;//第 i 个剩余类,给数位和贡献 j 的方案数
		}
	}
	f[0][0][0]=1;//考虑到第 i 个剩余类 ,数位和为 j ,取模结果为 k 时的方案数
	for(int i=0;i<p;++i)
		for(int j=0;j<=m;++j)
			for(int k=0;k<p;++k)
			{
				if(!f[i][j][k]) continue;
				for(int d=0;d<=min(m-j,cnt[i]*9);++d)// 当前考虑贡献 d 到数位和
					(f[i+1][j+d][(k+d*i)%p]+=f[i][j][k]*g[i][d])%=mod;
			}
	for(int i=1;i<=m;++i) (f[p][i][0]+=f[p][i-1][0])%=mod;
	for(int i=0;i<=m;++i) cout<<f[p][i][0]<<' ';
	return 0;
}

ZR2023 NOIP赛前20连测 Day7 T3 (强限制优先+调和级数)

题意

有 n 个人, 要分成若干组. 对于第 i 个人, 它所在的组的人数不能超过 ai, 求分组的方案数.

组与组之间是不可区分的, 每组的人也是无序的, 但人与人之间是可以区分的.

n3000,an

题解

由于大的组限制更强,所以我们贪心地考虑,排序之后根据组的大小从大到小考虑

fi,j 表示考虑到第 i 个组,有 j 个人还没有被分组的方案数。假设我们现在已经处理完了 i+1n ,考虑如何转移。没有被分组的加上当前组的大小 cnti 就是我们现在的人数。然后考虑给这些人分组,我们设 k 表示 i+1 的组的个数,那么每次的转移系数就为

(j+cntik×i)(k×ii,i,i)

第二个组合数下面有 ki

由于 k×ij+cnti ,因此 k 的个数是 logn 级别的

时间复杂度 O(n2logn)

ZR2023 NOIP赛前20连测 Day9 T3 (组合意义转多项式优化dp)

题意

假设存在 k 种不同的括号 (1(k,)1)k,定义:

若序列 S1,S2 为第一类括号序列,则 i,(iS1)iS1S2 均为第一类括号序列。

若序列 S1,S2 为第二类括号序列,则 i,(iS1)i,)iS1(i 与 S1S2 均为第二类括号序列。

空串既是第一类括号序列又是第二类括号序列。

简单来说,第一类括号序列只允许匹配时左括号在左边,右括号在右边,而第二类括号序列允许相反顺序的括号匹配。你的任务是,给定正整数 n,k,求出有 k 个不同括号之时,长度恰好为 2n 的第一类括号序列个数和第二类括号序列的个数。

由于答案可能很大,对 998244353 取模即可。

对于所有数据,1n106,1k109

题解

T=1 的情况是经典的卡特兰数,乘上括号选取的方案数 kn 即可

k=1,T=2 的情况考虑组合意义,我们就是要在 2n 的序列上选 n 个位置为左括号,剩下的为右括号,也就是 (2nn)

T=2 时,考虑直接乘选取方案数 kn 为啥不对。比如括号序列 ()() ,它既可以看成 (1,4),(2,3) 匹配,也可以看成 (1,2),(3,4) 匹配,也就是它可以从中间切分,这样就会算重,所以考虑 dp

fn 表示不可切分的括号序列个数,gn 表示括号序列的个数,那么有转移方程

fn=2k(gn1i=1n1fi2k×gni2k)

gn=i=1nfi×gni

第一个式子考虑容斥,总方案数 gn1 减掉不合法的方案即为合法方案(无切分)。枚举切分点 i ,钦定前 i 个一定合法(不可切分),后 ni 个随便填,注意两端括号选取的总方案数为 2k ,这样就可以算出不合法方案数

第二个式子同样考虑枚举切分点

接下来考虑使用 GF 技巧来快速计算上面的式子

我们设 FG 分别对应 f 数组和 g 数组的多项式,那么我们可以列出下面两个式子

F=1+2kxG12k(F1)(G1)

G=12F

第一个式子乘 x 是因为要整体右移一位,减 1 减去的是常数项

第二个式子考虑一个括号序列可以由多个不可切分的括号序列组成,所以式子形如

G=1+(F1)+(F1)2+

然后这个东西的封闭形式是经典的 11x ,把 F1 套进去就行

然后通过我们高超的初二数学技巧,我们解出来

G=k1(8k4)x+1k14k2x

1kk 就是一个只有常数项的单项式,114k2x 就是数列 pn=(4k2)n 所对应的多项式的封闭形式,这样我们只要把封闭形式为 1(8k4)x 的多项式的系数给求出来即可

然后这里题解给了一个很微妙的类似于求解常微分方程的做法,具体来说,设

H=1(8k4)x

H 求导得

H=48k21(8k4)x

分母有理化得

H=(24k)H1(8k4)x

然后考虑第 n 项的系数, H 就相当于是将 H 整体左移一位再乘上一个指数,也就是 (n+1)hn+1,右边分母的 x 乘到左边就相当于整体右移一位,即 nhn ,所以根据上面那个式子可以建立 hnhn+1 之间的方程:

(n+1)hn+1(8k4)nhn=(24k)hn

得到

hn+1=8kn4n4k+2n+1hn

这样这道题就做完了,由于只用求 [xn]G(x) ,所以时间复杂度 O(n)

代码里懒得线性求逆元了,所以复杂度是 O(nlogn)

posted on   star_road_xyz  阅读(62)  评论(0编辑  收藏  举报

相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】

导航

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5
点击右上角即可分享
微信分享提示