【题解】CF1264D2

题目大意

给定一个长度为n的字符串,其中只有(, ), ?三种字符,其中?可以为(或者)

对于一个括号序列,定义其权值为其通过删除字符后可以得到的合法的括号匹配的最深的深度,下面是一些括号匹配的例子:

深度为1:()

深度为2:(())

深度为3:((()))

下面这个例子是一个深度为0的括号序列,当然其权值也为0

深度为0:((

您希望求出所有可能的括号序列(即问号替换后)的权值,答案对998244353取模

题解

考虑最终对答案造成贡献的序列是什么样的,显然除了构成最深的括号子序列的括号是一一配对的,其余的问号都是左边的全是右括号,右边同理。
于是可以写出答案的式子,范德蒙德卷积化简得到最终的式子。
范德蒙德卷积应用:考虑组合意义。
考虑总贡献可以分析终态的形式,同时本题也启示对于正解的思考可以先做出最暴力的式子去化简或思考出高复杂度的方法消减不必要的时间。

#include<bits/stdc++.h>
using namespace std;
#define int long long
inline int rd(){
	int f=1,j=0;
	char w=getchar();
	while(!isdigit(w)){
		if(w=='-')f=-1;
		w=getchar();
	}
	while(isdigit(w)){
		j=j*10+w-'0';
		w=getchar();
	}
	return f*j;
}
const int N=1000010,mod=998244353;
int n,l,r,x,y,ans;
int inv[N],fps[N];
char s[N];
inline int pw(int x,int y){
	int ansn=1;
	while(y){
		if(y&1)ansn=ansn*x%mod;
		x=x*x%mod,y/=2;
	}
	return ansn;
}
inline int C(int x,int y){
	if(y<0||x<y)return 0;
//	cout<<"cal:"<<x<<" "<<y<<":"<<fps[x]*inv[y]%mod*inv[x-y]%mod<<"\n";
	return fps[x]*inv[y]%mod*inv[x-y]%mod;
}
signed main(){
	scanf("%s",s+1),n=strlen(s+1);
	fps[0]=inv[0]=1;
	for(int i=1;i<=n;i++)fps[i]=fps[i-1]*i%mod;
	inv[n]=pw(fps[n],mod-2);
	for(int i=n-1;i>=1;i--)inv[i]=inv[i+1]*(i+1)%mod;
	for(int i=1;i<=n;i++)r+=(s[i]==')'),y+=(s[i]=='?');
	for(int i=1;i<=n;i++){
		r-=(s[i]==')'),y-=(s[i]=='?');
		l+=(s[i]=='('),x+=(s[i]=='?');
//		cout<<i<<":"<<l<<" "<<r<<"-"<<x<<" "<<y<<":"<<x+y-1<<" "<<y-l+r-1<<" "<<C(x+y-1,y-l+r-1)<<"\n";
		ans+=l*C(x+y,y+r-l)%mod+x*C(x+y-1,y-l+r-1)%mod,ans%=mod;
	}
	printf("%lld\n",ans);
	return 0;
}
posted @   flywatre  阅读(22)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示