题解:CF1264D Beautiful Bracket Sequence
太笨了,其他题解写都没写的性质都看不出来……
Solution
easy version#
我们考虑没有 ?
的串怎么做。由于能无限删,留下 (((...)))
这种肯定不劣。记 (
数,)
数,答案即为
直接不太好做,最多也就是
性质 1:随着
变大, 不降, 不升, 上升。
较为显然。
性质 2:对于任意括号串,有且仅有一个位置满足
取到 且 。
证明:
- 随意找一个
取到 的位置 。令 为 。 - 若
,令 ,根据性质 1, 减小; - 若
,令 ,根据性质 1, 增大。 - 重复执行以上步骤直至
。此时即 。 - 因为
,总能找到 的位置。 - 随着移动变化的仅为
中较大者(若不是,就有更优的答案), 不变。
我们称上面提到的位置为「中间位」。
记 (
数,)
数,?
数,?
数。我们枚举「中间位」(
,右边恰好有 )
,答案即为:
复杂度
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#
对于硬版本,我们沿用前面的思路,考虑化简式子。
前面的
范德蒙特卷积:
解释一下第三步,我们从枚举
同样的方法化简前面的:
答案化简为
时间复杂度
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;
}
标签:
组合数学
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 为DeepSeek添加本地知识库
· 精选4款基于.NET开源、功能强大的通讯调试工具
· DeepSeek智能编程
· 大模型工具KTransformer的安装
· [计算机/硬件/GPU] 显卡