题解:CF1264D Beautiful Bracket Sequence

太笨了,其他题解写都没写的性质都看不出来……

Solution

easy version

我们考虑没有 ? 的串怎么做。由于能无限删,留下 (((...))) 这种肯定不劣。记 \(a_i\)\([1,i]\)( 数,\(b_i\)\((i,n]\)) 数,答案即为 \(\max_{i\in[1,n)}\min(a_i,b_i)\)

直接不太好做,最多也就是 \(\mathcal{O}(n^3)\) 的 DP。我们需要找一些性质。

性质 1:随着 \(i\) 变大,\(a_i\) 不降,\(b_i\) 不升,\(a_i-b_i\) 上升。

较为显然。

性质 2:对于任意括号串,有且仅有一个位置满足 \(\min(a_i,b_i)\) 取到 \(\max\)\(a_i=b_i\)

证明:

  • 随意找一个 \(\min(a_i,b_i)\) 取到 \(\max\) 的位置 \(p\)。令 \(x_p\)\(a_p-b_p\)
  • \(x_p>0\),令 \(p\gets p-1\),根据性质 1,\(x_p\) 减小;
  • \(x_p<0\),令 \(p\gets p+1\),根据性质 1,\(x_p\) 增大。
  • 重复执行以上步骤直至 \(x_p=0\)。此时即 \(a_p=b_p\)
  • 因为 \(x_i-x_{i-1}=1,x_0\le 0,x_n\ge 0\),总能找到 \(x_p=0\) 的位置。
  • 随着移动变化的仅为 \(a_i,b_i\) 中较大者(若不是,就有更优的答案),\(\min(a_i,b_i)\) 不变。

我们称上面提到的位置为「中间位」。

\(a_i\)\([1,i]\) 未填时的 ( 数,\(b_i\)\((i,n]\) 未填时的 ) 数,\(x_i\)\([1,i]\)? 数,\(y_i\)\((i,n]\)? 数。我们枚举「中间位」\(i\) 与答案 \(j\) 来计算,需要保证左边恰好有 \(j\)(,右边恰好有 \(j\)),答案即为:

\[\sum_{i=0}^{n}\sum_{j=0}^{n}j\binom{x_i}{j-a_i}\binom{y_i}{j-b_i} \]

复杂度 \(\mathcal{O}(n^2)\),可以通过 easy version。

typedef Mint<mod> MI;
int n, x, y, a, b; MI rs; Comb<MI> C; string s;
int main() {
	cin >> s, n = s.size(), s = "#" + s, C.init(n);
	REP(i, 1, n) {
		if (s[i] == '?') y ++;
		if (s[i] == ')') b ++;
	}
	REP(i, 1, n) { // i=0 时贡献必为 0,可以省略
		if (s[i] == '(') a ++;
		if (s[i] == '?') x ++, y --;
		if (s[i] == ')') b --;
		REP(j, 0, n)
			rs += C(x, j - a) * C(y, j - b) * j;
	}
	cout << rs << '\n';
	return 0;
}

hard version

对于硬版本,我们沿用前面的思路,考虑化简式子。

前面的 \(\sum_{i=0}^{n}\) 很难化简,我们化简后面的那个求和。\(j\) 这个系数很讨厌,可以将其化为 \((j-a_i)+a_i\),然后想办法塞进组合数里。

\[\begin{aligned} &\sum_{j=0}^{n}j\binom{x_i}{j-a_i}\binom{y_i}{j-b_i}\\ =&\sum_{j=0}^{n}(j-a_i)\binom{x_i}{j-a_i}\binom{y_i}{j-b_i}+\sum_{j=0}^{n}a_i\binom{x_i}{j-a_i}\binom{y_i}{j-b_i}\\ \end{aligned} \]

\(m\binom{n}{m}\) 的化简方法:\(m\binom{n}{m}=\frac{n!m}{m!(n-m)!}=\frac{(n-1)!n}{(m-1)!(n-m)!}=n\binom{n-1}{m-1}\)

\[\begin{aligned} =&\sum_{j=0}^{n}x_i\binom{x_i-1}{j-a_i-1}\binom{y_i}{j-b_i}+\sum_{j=0}^{n}a_i\binom{x_i}{j-a_i}\binom{y_i}{j-b_i}\\ =&x_i\sum_{j=0}^{n}\binom{x_i-1}{j-a_i-1}\binom{y_i}{j-b_i}+a_i\sum_{j=0}^{n}\binom{x_i}{j-a_i}\binom{y_i}{j-b_i} \end{aligned} \]

范德蒙特卷积:\(\sum_{i=0}^{n}\binom{n}{i}\binom{m}{k-i}=\binom{n+m}{k}\)。我们接下来利用它来化简。

\[\begin{aligned} &a_i\sum_{j=0}^{n}\binom{x_i}{j-a_i}\binom{y_i}{j-b_i}\\ =&a_i\sum_{j=0}^{n}\binom{x_i}{x-j+a_i}\binom{y_i}{j-b_i}\\ =&a_i\sum_{j=0}^{n}\binom{x_i}{x_i-j-b_i+a_i}\binom{y_i}{j}\\ =&a_i\binom{x_i+y_i}{x_i+a_i-b_i} \end{aligned} \]

解释一下第三步,我们从枚举 \(j\) 变为枚举 \((j-b_i)\),因为原来 \(j\) 超出上下界时后面的项乘积为 \(0\),所以范围不用特意改变。

同样的方法化简前面的:

\[\begin{aligned} &x_i\sum_{j=0}^{n}\binom{x_i-1}{j-a_i-1}\binom{y_i}{j-b_i}\\ =&x_i\sum_{j=0}^{n}\binom{x_i-1}{x_i-j+a_i}\binom{y_i}{j-b_i}\\ =&x_i\sum_{j=0}^{n}\binom{x_i-1}{x_i-j-b_i+a_i}\binom{y_i}{j}\\ =&x_i\binom{x_i+y_i-1}{x_i+a_i-b_i} \end{aligned} \]

答案化简为

\[\sum_{i=0}^{n}a_i\binom{x_i+y_i}{x_i+a_i-b_i}+x_i\binom{x_i+y_i-1}{x_i+a_i-b_i} \]

时间复杂度 \(\mathcal{O}(n)\),可以通过 hard ersion。

typedef Mint<mod> MI;
int n, x, y, a, b; MI rs; Comb<MI> C; string s;
int main() {
	cin >> s, n = s.size(), s = "#" + s, C.init(n);
	REP(i, 1, n) {
		if (s[i] == '?') y ++;
		if (s[i] == ')') b ++;
	}
	REP(i, 1, n) { // i=0 时贡献必为 0,可以省略
		if (s[i] == '(') a ++;
		if (s[i] == '?') x ++, y --;
		if (s[i] == ')') b --;
		rs += C(x + y, x + a - b) * a + C(x + y - 1, x + a - b) * x;
	}
	cout << rs << '\n';
	return 0;
}
posted @ 2024-09-03 07:02  喵仔牛奶  阅读(8)  评论(0编辑  收藏  举报