PPIIIGG
PPIIIGG
题目描述
在超级猪星上,超级小猪研究员发现了一个仅由字符 P、I、G 组成的字符串 $S$。现在需要统计其中有多少个 超级 PIG 序列。
一个 超级 PIG 序列 需要满足以下条件:
- 它由 $a$ 个
P、$b$ 个I、$c$ 个G依次拼接而成,即形如 $\underbrace{PP\cdots P}_{a}\underbrace{II\cdots I}_{b}\underbrace{GG\cdots G}_{c}$。 - $a, b, c \ge 1$。
- 数量关系满足:$a + c - 1 \le b$。
你需要计算在给定的字符串 $S$ 中,有多少个子序列是 超级 PIG 序列。答案对 $10^9+7$ 取模。
对于一个序列,删除任意个任意位置的字符后得到的新非空序列是原序列的子序列。如 abcde 包含 abcde、ace 等子序列。
输入描述:
第一行包含一个整数 $T \left(1 \le T \le 10^4\right)$,表示测试数据组数。
接下来每组数据:
第一行包含一个整数 $n \left(1 \le n \le 1000\right)$,表示字符串长度。
第二行包含一个长度为 $n$ 的字符串 $S$,仅由大写字母 P、I、G 组成。
保证所有测试数据的 $n^2$ 之和不超过 $10^7$。
输出描述:
对于每组数据,输出一行一个整数,表示满足条件的子序列数量对 $10^9+7$ 取模后的结果。
示例1
输入
2
4
PIIG
7
PPIIIGG
输出
3
45
解题思路
给出本题的组合数学做法。前置知识需要了解范德蒙德卷积,即 $$\sum\limits_{i=0}^{k}{\binom{n}{i}\binom{m}{k-i}} = \binom{n+m}{k} \tag{1}$$
由于子序列具有 $P \dots P \mid I \dots I \mid G \dots G$ 的分段结构,习惯上我们会枚举中间字符 I 的数量 $b$。按子序列中字符 I 的数量 $b$ 进行分类讨论。
首先考虑 $b=1$ 的情况。此时子序列中仅有一个 I,约束条件变为 $a+c \leq 2$。又因为 $a, c \ge 1$,此时只能在 I 左侧选择恰好 $1$ 个 P,在右侧选择恰好 $1$ 个 G。假设 I 左侧有 $a$ 个 P,右侧有 $c$ 个 G,则以该 I 为中间字符的合法子序列数量为 $$a \cdot c \tag{2}$$
为了确定 $a$ 与 $c$ 的数量,我们根据子序列中最左边与最右边的 I 的位置对子序列进行分类。设子序列中最左边与最右边的 I 的位置分别是 $l$ 和 $r$,此时我们必选 $l$ 和 $r$ 位置上的 I。为了方便,在接下来的推导过程中,我们暂时用 $a$ 表示 $l$ 左侧 P 的数量,用 $c$ 表示 $r$ 右侧 G 的数量,用 $b$ 表示区间 $[l,r]$ 中 I 的数量。
先确定除必选的 $l$ 和 $r$ 位置的 I 外,额外选择的 I 的数量 $i \left(0 \leq i \leq b-2\right)$。再根据约束 $a+c \leq b+1$ 确定选择 P 和 G 的总数 $j \left( 2 \leq j \leq i+3 \right)$。最后分配具体的 P 和 G 的数量。因此,在 I 的数量至少为 $2$、且最左边与最右边的 I 分别位于 $l$ 与 $r$ 的子序列数量为 $$\sum\limits_{i=0}^{b-2}{\binom{b-2}{i} \sum\limits_{j=2}^{i+3}{\sum\limits_{k=1}^{j-1}{\binom{a}{k} \binom{c}{j-k}}}} \tag{3}$$
对于 $(3)$ 式最内层的求和 $\sum\limits_{k=1}^{j-1}{\binom{a}{k} \binom{c}{j-k}}$,利用范德蒙德卷积 $(1)$ 进行变形:$$\begin{align*} &\sum\limits_{k=1}^{j-1}{\binom{a}{k} \binom{c}{j-k}} \\ =&\sum\limits_{k=0}^{j}{\binom{a}{k} \binom{c}{j-k}} - \binom{a}{0}\binom{c}{j} - \binom{a}{j}\binom{c}{0} \\ =&\binom{a+c}{j} - \binom{c}{j} - \binom{a}{j} \end{align*} \tag{4}$$
以为本题无法用组合数学求解
这是范德蒙德卷积的一个推论,有如下组合恒等式:$$\sum\limits_{k=0}^{n}{\binom{n}{k}} \sum\limits_{j=0}^{k+d}{\binom{m}{j}} = \sum\limits_{j=0}^{n+d}{\binom{n+m}{j}} \tag{6}$$
等式左边可分两步:先把 $n+m$ 个物品分成大小分别为 $n$ 和 $m$ 的两组,第一步从 $n$ 个物品中选出 $k \left(0 \leq k \leq n\right)$ 个,第二步从 $m$ 个物品中选出 $j$ 个,使得总数不超过 $n+d$。其中第一步方案数为 $\binom{n}{k}$,第二步方案数为 $\sum\limits_{j=0}^{n+d-k} \binom{m}{j}$。故总的方案数为 $$\sum\limits_{k=0}^{n}{\binom{n}{k}} \sum\limits_{j=0}^{n+d-k}{\binom{m}{j}} \tag{7}$$
再令 $k = n - k'$,则 $\sum\limits_{k=0}^{n}{\binom{n}{k}} \sum\limits_{j=0}^{n+d-k}{\binom{m}{j}} = \sum\limits_{k'=0}^{n}{\binom{n}{n-k'}} \sum\limits_{j=0}^{k'+d}{\binom{m}{j}}$。由于 $\binom{n}{n-k'} = \binom{n}{k'}$,且求和结果与顺序无关,因此 $(7)$ 与 $(6)$ 等价。
能想到这个的真神人了,只能说组合数学还是太吃天赋了。
利用恒等式 $(6)$ 对 $(5)$ 式中形如 $\sum\limits_{i=0}^{b-2}{\binom{b-2}{i} \sum\limits_{j=2}^{i+3}{\binom{x}{j}}}$ 的部分进行化简:$$\begin{align*}&\sum_{i=0}^{b-2}{\binom{b-2}{i} {\sum_{j=2}^{i+3}{\binom{x}{j}}}} \\ =& \sum_{i=0}^{b-2}{\binom{b-2}{i} \left({\sum_{j=0}^{i+3}{\binom{x}{j}}} - \binom{x}{0} - \binom{x}{1}\right)} \\ =& \sum_{i=0}^{b-2}{\binom{b-2}{i} {\sum_{j=0}^{i+3}{\binom{x}{j}}}} - (x + 1)\sum_{i=0}^{b-2}{\binom{b-2}{i}} \\ =& \sum_{j=0}^{b+1}\binom{b-2+x}{j} - (x + 1)2^{b-2} \end{align*} \tag{8}$$
定义前缀和 $S_i(k) = \sum\limits_{j=0}^{k}{\binom{i}{j}}$,则 $(8)$ 式可进一步写成 $$\sum\limits_{i=0}^{b-2}{\binom{b-2}{i} \sum\limits_{j=2}^{i+3}{\binom{x}{j}}} = S_{b-2+x}(b+1) - (x+1)2^{b-2} \tag{9}$$
将 $(9)$ 代回 $(5)$,得到固定 $l, r$ 时的方案数为 $$S_{b-2+a+c}(b+1) - (a+c+1)2^{b-2} - \left(S_{b-2+a}(b+1) - (a+1)2^{b-2}\right) - \left(S_{b-2+c}(b+1) - (c+1)2^{b-2}\right) \tag{10}$$
最后,我们将所有情况累加。用 $a_{l \sim r}$、$b_{l \sim r}$、$c_{l \sim r}$ 分别表示区间 $[l,r]$ 中字符 P、I、G 的数量。综合 $(2)$ 式和 $(10)$ 式,最终答案为 $$\sum\limits_{i=1}^{n}{[s_i = \mathtt{I}]}\left(a_{1 \sim i-1} \cdot c_{i+1 \sim n}\right) \; \mathbf{+} \; \sum\limits_{l=1}^{n}{[s_l = \mathtt{I}] \sum\limits_{r=l+1}^{n}{[s_r = \mathtt{I}] \Big(S_{B-2+A+C}(B+1) - (A+C+1)2^{B-2} - \left(S_{B-2+A}(B+1) - (A+1)2^{B-2}\right) - \left(S_{B-2+C}(B+1) - (C+1)2^{B-2}\right)\Big)}} \tag{11}$$
其中 $A = a_{1 \sim l-1}$,$B = b_{l \sim r}$,$C = c_{r+1 \sim n}$。
AC 代码如下,时间复杂度为 $O\left(n^2\right)$:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1005, M = N * 3, mod = 1e9 + 7;
int c[M][M], s[M][M];
char str[N];
int f[N][26];
void init() {
for (int i = 0; i < M; i++) {
for (int j = 0; j <= i; j++) {
if (!j) c[i][j] = 1;
else c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % mod;
}
}
for (int i = 0; i < M; i++) {
s[i][0] = 1;
for (int j = 1; j < M; j++) {
s[i][j] = (s[i][j - 1] + c[i][j]) % mod;
}
}
}
int get(int b, int x) {
return (s[b - 2 + x][b + 1] - (x + 1ll) * s[b - 2][b - 2]) % mod;
}
void solve() {
int n;
cin >> n >> str;
memmove(str + 1, str, n + 1);
for (int i = 1; i <= n; i++) {
for (int j = 0; j < 26; j++) {
f[i][j] = f[i - 1][j];
}
f[i][str[i] - 'A']++;
}
int ret = 0;
for (int i = 1; i <= n; i++) {
if (str[i] != 'I') continue;
int a = f[i - 1]['P' - 'A'];
int c = f[n]['G' - 'A'] - f[i]['G' - 'A'];
ret = (ret + 1ll * a * c) % mod;
}
for (int l = 1; l <= n; l++) {
if (str[l] != 'I') continue;
for (int r = l + 1; r <= n; r++) {
if (str[r] != 'I') continue;
int a = f[l - 1]['P' - 'A'];
int b = f[r]['I' - 'A'] - f[l - 1]['I' - 'A'];
int c = f[n]['G' - 'A'] - f[r]['G' - 'A'];
ret = (ret + get(b, a + c)) % mod;
ret = (ret - get(b, a)) % mod;
ret = (ret - get(b, c)) % mod;
}
}
ret = (ret + mod) % mod;
cout << ret << '\n';
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
init();
int t;
cin >> t;
while (t--) {
solve();
}
return 0;
}
参考资料
【规律未来杯】2026 广东工业大学校赛(同步赛):https://ac.nowcoder.com/acm/contest/130542
本文来自博客园,作者:onlyblues,转载请注明原文链接:https://www.cnblogs.com/onlyblues/p/19762554

浙公网安备 33010602011771号