• Codeforces 1264D


    Codeforces 题面传送门 & 洛谷题面传送门

    首先对于这样的题目,我们应先考虑如何计算一个括号序列 (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),那么这个点的贡献为:

    [sumlimits_{i=0}^a(i+b)dbinom{a}{i}dbinom{c}{i+b-d} ]

    然后括号拆拆,组合恒等式推推:

    [egin{aligned} &sumlimits_{i=0}^a(i+b)dbinom{a}{i}dbinom{c}{i+b-d}\ =&sumlimits_{i=0}^aidbinom{a}{i}dbinom{c}{i+b-d}+bsumlimits_{i=0}^adbinom{a}{i}dbinom{c}{i+b-d}\ =&sumlimits_{i=0}^aadbinom{a-1}{i-1}dbinom{c}{i+b-d}+bsumlimits_{i=0}^adbinom{a}{i}dbinom{c}{i+b-d}\ =&asumlimits_{i=0}^adbinom{a-1}{a-i}dbinom{c}{i+b-d}+bsumlimits_{i=0}^adbinom{a}{a-i}dbinom{c}{i+b-d}\ =&adbinom{a-1+c}{a+b-d}+bdbinom{a+c}{a+b-d} end{aligned} ]

    预处理一下简单算算即可。

    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
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    团队开发项目客户端——游戏子系统的设计(上)
    团队开发项目客户端——注册子系统的设计
    团队项目开发客户端——登录子系统的设计
    协程库
    Linux下用命令查看CPU ID以及厂家等信息
    c++中字符串的截取:
    C++ STL 的各结构实现
    关于mysql查询最近一条记录
    BerkeleyDB原理及其对应API
    高性能服务器设计(Jeff Darcy's notes on high-performance server design
  • 原文地址:https://www.cnblogs.com/ET2006/p/Codeforces-1264D.html
Copyright © 2020-2023  润新知