PPIIIGG

PPIIIGG

题目描述

在超级猪星上,超级小猪研究员发现了一个仅由字符 PIG 组成的字符串 $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 包含 abcdeace 等子序列。

输入描述:

第一行包含一个整数 $T \left(1 \le T \le 10^4\right)$,表示测试数据组数。

接下来每组数据:

第一行包含一个整数 $n \left(1 \le n \le 1000\right)$,表示字符串长度。

第二行包含一个长度为 $n$ 的字符串 $S$,仅由大写字母 PIG 组成。

保证所有测试数据的 $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}$$

  接着考虑 $b > 1$ 的情况。为了确定 $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$ 确定选择 PG 的总数 $j \left( 2 \leq j \leq i+3 \right)$。最后分配具体的 PG 的数量。因此,在 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}$$

  将 $(4)$ 代入 $(3)$ 可得 $$\begin{align*}&\sum\limits_{i=0}^{b-2}{\binom{b-2}{i} \sum\limits_{j=2}^{i+3}{\left(\binom{a+c}{j} - \binom{a}{j} - \binom{c}{j}\right)}} \\ =& \sum\limits_{i=0}^{b-2}{\binom{b-2}{i} \sum\limits_{j=2}^{i+3}{\binom{a+c}{j}}} - \sum\limits_{i=0}^{b-2}{\binom{b-2}{i} \sum\limits_{j=2}^{i+3}{\binom{a}{j}}} - \sum\limits_{i=0}^{b-2}{\binom{b-2}{i} \sum\limits_{j=2}^{i+3}{\binom{c}{j}}} \end{align*} \tag{5}$$

  由于需要枚举 $l$ 和 $r$,还要枚举 I 的数量,因此直接计算 $(5)$ 式的总复杂度是 $O\left(n^3\right)$。赛时推导到这里就不会了,以为本题无法用组合数学求解。赛后试着问了下 Genimi,实际上对于形如 $\sum\limits_{k=0}^{n}{\binom{n}{k}} \sum\limits_{j=0}^{k+d}{\binom{m}{j}}$ 的组合数求和可以进一步化简。

  这是范德蒙德卷积的一个推论,有如下组合恒等式:$$\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+d$ 个物品的方案数。等式左边可分两步:先把 $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]$ 中字符 PIG 的数量。综合 $(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

posted @ 2026-03-24 11:18  onlyblues  阅读(4)  评论(0)    收藏  举报
Web Analytics