CF1264D Beautiful Bracket Sequence
题面传送门
我们考虑怎么确定一个序列的深度。
可以肯定的是我们选出来的子序列一定是长度为\(2x\)的,前\(x\)个为\((\),后\(x\)为\()\)
如果一个序列是确定的,我们显然可以维护两个值\(d1,d2\)表示当前位置左边的\((\)个数与右边的\()\)个数。
因为每次要么是\(d1\)加一,要么是\(d2\)减一,所以这个位置是确定的。
这就启发我们枚举这个位置。
设左边的\((\)个数为\(l1\),\(?\)为\(l2\),右边为\(r1\)与\(r2\)
假设右边所有\(?\)都变成\()\)则我们可以设\(d=r1+r2-l1\)表示左边要变成\((\)的个数。
然后我们枚举左边变成的个数就可以得到式子\(\sum\limits_{i=0}^{d}{(i+l1)C^{l2}_{i}C_{r2}^{d-i}}\)
然后随便\(O(n)\)预处理一下这个东西就可以\(O(n^2)\)计算了。
这个式子肯定有办法化简,让我们把它拆开来。
\(l1\sum\limits_{i=0}^{d}{C^{l2}_{i}C_{r2}^{d-i}}\)与\(\sum\limits_{i=0}^{d}{iC^{l2}_{i}C_{r2}^{d-i}}\)
前面那个显然是\(l1C^{l2+r2}_{i}\),后面那个是这样的:
\(\sum\limits_{i=0}^{d}{l2C^{l2-1}_{i-1}C_{r2}^{d-i}}=l2C_{d-1}^{l2+r2-1}\)
然后就可以算了,时间复杂度\(O(n)\)
code:
#include <vector>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<cmath>
#include<algorithm>
#include<bitset>
#include<set>
#include<map>
#define I inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
#define l(x) x<<1
#define r(x) x<<1|1
#define re register
#define ll long long
#define db double
#define N 1000000
#define eps (1e-5)
#define mod 998244353
#define U unsigned
using namespace std;
int n,l1,l2,r1,r2,d;char s[N+5];ll inv[N+5],frc[N+5],now,ans;
I ll mpow(ll x,int y=mod-2){ll ans=1;while(y) y&1&&(ans=ans*x%mod),y>>=1,x=x*x%mod;return ans;}
int main(){
freopen("1.in","r",stdin);
re int i;scanf("%s",s+1);n=strlen(s+1);frc[0]=1;
for(i=1;i<=n;i++) r1+=(s[i]==')'),r2+=(s[i]=='?');
for(i=1;i<=n;i++) frc[i]=frc[i-1]*i%mod;now=mpow(frc[n]);for(i=n;~i;i--) inv[i]=now,now=now*i%mod;
for(i=1;i<n;i++){
l1+=(s[i]=='(');l2+=(s[i]=='?');r1-=(s[i]==')');r2-=(s[i]=='?');if(l1+l2<r1||r1+r2<l1) continue;d=r1+r2-l1;
ans+=inv[l2+r2-d]*(l1*frc[l2+r2]%mod*inv[d]%mod+l2*frc[l2+r2-1]%mod*inv[d-1]%mod)%mod;
}
printf("%lld\n",ans%mod);
}