暑假数学1

A [ABC281G] Farthest City

构造一张 \(N\) 个点的无向连通图,边权都是 \(1\)。记图中 \(1\)\(u\) 的最短路径长度为 \(d_u\),你需要保证 \(\max\{d_1,d_2,...,d_{N-1}\}\) 严格小于 \(d_N\)。求构造方案数模 \(M\) 的值,方案区分节点编号。

发现一些很好的性质:

  • \(1\)\(d_N\) 的所有距离都有点。所有点的距离去重就是 \(1\)\(d_N\) 的排列。
  • 考虑像 BFS 一样按照从 \(1\) 号点搜的距离来对这个图分层,发现第 \(i\) 层的每一个点都至少跟上一层的一个点相连,且仅能跟上一层的点相连,每一层内可以相连。

那么我们发现它可以 \(\text{dp}\) ,考虑 \(f_{i,j}\) 记录这个图中前 \(i\) 个点,按深度分的最后一层上有 \(j\) 个点的答案。

  • 首先,我们最后需要输出的答案是 \(f_{n,1}\) 即全部 \(n\) 个点,最后一层是终点 \(n\)
  • 初始化,就是 \(f_{1,1} = 1\) 即第一个起点只有一种方案。

现在考虑转移,我们首先需要枚举一下 \(i\),然后枚举一下 \(j\),这时候考虑如何转移 \(f_{i,j}\)

我们发现 \(f_{i,j}\) 究竟答案是多少取决于上一层的点的个数,考虑枚举一下,设其为 \(k\)。那么 \(k\) 的范围及应该是 \([1,i-j]\),值得注意的是,理论 \(k\) 应该取不到 \(i-j\),但多算一点对答案没有影响,而且在最开始 \(j\) 表示深度为 \(1\) 的那一层是,就必须考虑 \(k=i-j\) 的情况了,为了简便,就不需要分情况写了。

现在我们拿到了三个变量,可以正式开始推式子了。

我们得到:

\[ f_{i,j} = \sum\limits_{k=1}^{i-j}\color{red}{f_{i-j,k}}\color{green}{\dbinom{n-(i-j)-1}{j}}\color{brown}{2^{\frac{j(j-1)}{2}}}\color{blue}{(2^k-1)^j} \]

我将这个方程分成了 \(4\) 部分,下面将逐一进行解释:

  • \(\color{red}{f_{i-j,k}}\):我们枚举了上一层的个数 \(k\),那么自己画画就能知道,就应该在现在的 \(i\) 中减掉这一层的 \(j\) 后剩余的点中,最后一层就是 \(k\) 个了,那么就是从 \(f_{i-j,k}\) 转移过来了。

  • \(\color{green}{\dbinom{n-(i-j)-1}{j}}\):考虑这一层的 \(j\) 个点有多少种可以选择的标号。包括上一层的那些点,已经用了 \(i-j\) 个标号,最后的终点也用了一个,那么总的数量就是 \(n-(i-j)-1\),在里面选 \(j\) 个就行,预处理组合数。

  • \(\color{brown}{2^{\frac{j(j-1)}{2}}}\) 可能 \(\LaTeX\) 这里不太清楚,是次方。这里我们考虑这一层的 \(j\) 个点互相连有几种选法。我们知道 \(j\) 个节点的完全图的边数是 \(\frac{j(j-1)}{2}\),在这些边中我们可以任意选择若干,那么每一条边都有两种情况:选或不选,那么就是 \(2^{\frac{j(j-1)}{2}}\) 种。

  • \(\color{blue}{(2^k-1)^j}\) 然后考虑 \(j\) 那层和 \(k\) 那层之间连边的情况。每一个 \(j\) 是孤立的,分开讨论。拿出一个 \(j\) 里的点看,它可以任选若干 \(k\) 里的点连,就有 \(2^k\) 种,但不能一个都不选,减掉即可。这里是 \(j\) 个点,所以乘法原理就得到了答案。

最后答案相加即可。

于是我们就得到了状态转移方程,初始化一些必要的量,比如组合数,\(2^n\)\((2^k-1)^j\),时间复杂度 \(O(n^3)\)

特别注意的是,在 \(i = n\) 的时候,终点的标号有一种选法,只需要在初始化的时候把 \(C_{0,i}\) 都变成 \(1\) 就行。

signed main()
{
	#ifdef LOCAL
	freopen("in.in","r",stdin);
	#endif
	n = read(),MOD = read();
	fac[0] = 1;
	for(int i{1};i<=n*n;i++) fac[i] = (fac[i-1]*2) % MOD;
	for(int i{1};i<=n;i++) C[i][0] = 1,C[i][1] = i;
	C[2][1] = 2,C[2][2] = 1;
	for(int i{3};i<=n;i++)
		for(int j{1};j<=i;j++) C[i][j] = (C[i-1][j]+C[i-1][j-1]) % MOD;
	for(int i{1};i<=n;i++) _2k1[i][0] = 1,C[0][i] = 1;
	for(int i{1};i<=n;i++)
	for(int j{1};j<=n;j++)
		_2k1[i][j] = _2k1[i][j-1] * (fac[i]-1) % MOD;
	f[1][1] = 1;
	for(int i{1};i<=n;i++)
		for(int j{1};j<i;j++)
			for(int k{1};k<=i-j;k++)
				(f[i][j] += f[i-j][k] * C[n-i+j-1][j] % MOD * fac[j*(j-1)/2] % MOD * _2k1[k][j] % MOD) %= MOD;
	writeln(((f[n][1] % MOD )+ MOD) % MOD);
	exit(0);
}

B [ABC305G] Banned Substrings

给定正整数 \(n\)\(m\) 以及 \(m\) 个字符串 \(s_1\sim s_m\)

求满足以下条件的,长度为 \(n\),只含字母 \(\texttt{a}\)\(\texttt{b}\) 的字符串 \(S\) 的个数  \(\bmod\ 998244353\)

  • \(\forall1\le i\le m\)\(s_i\) 不是 \(S\) 的连续字串。

\(n\le10^{18},m\le126,s_i\) 只含字母 \(\texttt{a}\)\(\texttt{b}\)\(L=\left\vert s_i\right\vert\le6\)

考虑设 \(f_{i,s}\) 表示填到第 \(i\) 位,最后 \(5\) 位的字符串为 \(S\) 的答案数量,转移是 \(O(nm2^5)\) 的。

然而 \(n\) 非常大,考虑矩阵优化。

如果一个状态 \(X\) 可以转到另一个状态 \(Y\)(当然不能让某个 \(s_i\) 成为子串),令 \(M_{X,Y}=1\),否则 \(M_{X,Y}=0\)

然后我们算出 \(M^{n-5}\),把结果的所有点的值加起来即可。

(如果 \(n\le5\),直接特判并暴力枚举即可。)

时间复杂度 \(\Theta(\log n\cdot(2^{5})^3)\)

G [雅礼集训 2018 Day10] 足球大战

\[\displaystyle\sum_{i=1}^{n} p^{i} (1-p)^{n-i} { \binom{n}{i}} \sum_{j=0}^{i-1} q^j (1-q)^{n-j} {n \choose j} \]

式子比较显然,考虑算这个东西。由于空间只有 \(64 \text{MiB}\),但是 long long 是必须开的,而且 \(n\)\(10^7\) ,所以考虑删掉一些预处理的数组,并且必须 \(O(n)\) 计算上式。

发现组合数只需要所有阶乘逆元和 \(n!\),那么只开一个数组存阶乘逆元,再开一个变量存 \(n!\) 就行了。

接下来发现可以每次递推 \(j=i-1,q^j(1-q)^{n-j} \binom{n}{j}\) 累计一下后面这一坨就可以把复杂度优化到 \(O(n\log n)\),然后拿到 \(84 \sim 88\) 分。考虑到不能每次都用快速幂,所以把 \(p^i,(1-p)^{n-i},q^j,(1-q)^{n-j}\) 开四个变量都递推一下就好了。

这时候发现我们收获了校内 \(\text{OJ}\) \(94\) 分的好成绩,再测一下样例发现第二个过不去,然而本人懒得特判,于是对 \(n\) 进行数据分治。

\(O(n)\) 但无特判:

	int ans{};
	int res2{};
	int pi = 1; //p^i
	int qj = 1; //p^j
	int inv_1p = qp(_1p,MOD-2); //inv(1-p)
	int inv_1q = qp(_1q,MOD-2); //inv(1-q)
	int _1pn_i = qp(_1p,n-1);
	int _1qn_i = qp(_1q,n);
	for(int i{1};i<=n;i++)
	{
		(pi *= p) %= MOD;
		
		int res1 =  pi * _1pn_i % MOD * getC(n,i) % MOD;
		(_1pn_i *= inv_1p) %= MOD;
		int j = i-1;//n^2 -> n
		(res2 += qj * _1qn_i % MOD * getC(n,j) % MOD) %= MOD;
		(qj *= q) %= MOD;
		(_1qn_i *= inv_1q) %= MOD;
		(res1 *= res2) %= MOD;
		(ans += res1) %= MOD;
	}
	writeln(ans);
posted @ 2024-09-14 21:09  WanGMiNgWeI  阅读(7)  评论(0编辑  收藏  举报