Codeforces 1264D - Beautiful Bracket Sequence(组合数学)
首先对于这样的题目,我们应先考虑如何计算一个括号序列 \(s\) 的权值。一件非常显然的事情是,在深度最深的、是原括号序列的子序列的括号序列中,必定存在一个满足前面只由一段左括号,后面只由一段右括号组成,因此我们考虑枚举这中间位置在原括号序列中对应哪个位置,那么假设这个断点位于 \(i\) 和 \(i+1\) 之间,我们设 \(i\) 及之前有 \(x\) 个左括号,\(i+1\) 及之后有 \(y\) 个右括号,那么显然以这个位置为端点的括号序列的深度就是 \(\min(x,y)\),注意到这里涉及一个 \(\min\),一脸不好直接维护的样子,不过注意一件事情,那就是你这个 \(i\) 每往后移一格,\(x-y\) 就会恰好增加 \(1\),也就是说必然恰好存在一个断点满足 \(x=y\),在此之前,\(x<y\),因此 \(\min(x,y)=x\),在此之后,\(x>y\),因此 \(\min(x,y)=y\),又因为 \(x\) 随 \(i\) 的增大单调不增,\(y\) 随 \(i\) 的增大单调不降,因此在这个断点前必然有 \(\min(x,y)<\) 断点处的 \(x\),在这个断点之后必然有 \(\min(x,y)>\) 断点处的 \(x\),因此这个断点处的 \(x\) 就是该括号序列所有由一段左括号+一段右括号组成的合法括号序列中,深度最大的那一个,也就是说:
Conclusion. 一个括号序列的权值,等于其所有相邻位置 \(i,i+1\) 中,满足 \(i\) 及之前左括号个数等于 \(i+1\) 之后的右括号个数的 \(i\) 之前的左括号个数。
接下来此题就变成一个组合数学问题了,考虑枚举这个断点 \(i\),假设 \(i\) 前面问号个数为 \(a\),左括号个数为 \(b\),\(i+1\) 后面问号个数为 \(c\),右括号个数为 \(d\),那么这个点的贡献为:
然后括号拆拆,组合恒等式推推:
预处理一下简单算算即可。
const int MAXN=1e6;
const int MOD=998244353;
char s[MAXN+5];int n;
int fac[MAXN*2+5],ifac[MAXN*2+5];
void init_fac(int n){
for(int i=(fac[0]=ifac[0]=ifac[1]=1)+1;i<=n;i++) ifac[i]=1ll*ifac[MOD%i]*(MOD-MOD/i)%MOD;
for(int i=1;i<=n;i++) fac[i]=1ll*fac[i-1]*i%MOD,ifac[i]=1ll*ifac[i]*ifac[i-1]%MOD;
}
int binom(int x,int y){
if(x<0||y<0||x<y) return 0;
return 1ll*fac[x]*ifac[y]%MOD*ifac[x-y]%MOD;
}
int main(){
scanf("%s",s+1);n=strlen(s+1);init_fac(MAXN+5);int s1=0,s2=0,ans=0;
for(int i=1;i<=n;i++) s1+=(s[i]==')'),s2+=(s[i]=='?');
for(int i=1,x=0,l=0,c=0;i<=n;i++){
x+=(s[i]=='?');l+=(s[i]=='(');c+=(s[i]==')');int y=s2-x,r=s1-c;
ans=(ans+1ll*l*binom(x+y,y+r-l)+1ll*x*binom(y+x-1,y-l+r-1))%MOD;
} printf("%d\n",ans);
return 0;
}
原文地址:https://www.cnblogs.com/ET2006/p/Codeforces-1264D.html
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 浅谈mybatis中的占位符
- Python | 详解Python中的协程,为什么说它的底层是生成器?
- 初识Mybatis中的动态sql
- Raw use of parameterized class 'Future'
- javaweb遇到的报错问题以及解决方案(持续更新)
- Spark Java UDAF 输入struct嵌套结构
- 深入理解Java内存模型
- Mybatis高级查询(一):resultMap与resultType
- JDK错误用法—TimSort
- Mybatis高级查询(三):分页查询
- 以OpenResty搭建RTB竞价引擎接入层
- 优化Linux bootloader速度的究极之路:从GRUB到EFI Stub
- Linux--nc命令
- Netty之美--I/O模型
- 023.基于IT论坛案例学习Elasticsearch(二):Query高级知识(一)