考虑(D1)的(O(n^2)),我们直接进行组合处理。
考虑在(p)这个位置,左边有(l)个(,右边有(r)个),左边有(l)个问号,右边有(r)个问号。
这个位置的贡献为:
(sum_{i = 0} ^ x (l+i)inom{x}{i}inom{y}{l + i - r})
考虑我们拆项。
(lsum_{i = 0} ^ xinom{x}{i}inom{y}{l + i - r} + sum_{i = 0} ^ x iinom{x}{i}inom{y}{l + i - r})
考虑前者可以写作(linom{x + y}{r + y - l})
后者把(i)吸收进去,(x)提取出来
(xinom{x + y - 1}{r + y - l - 1})
那么一个点的贡献是(linom{x + y}{r + y - l} + xinom{x + y - 1}{r + y - l - 1})
#include<iostream>
#include<cstdio>
#include<cstring>
#define ll long long
#define N 1000005
#define mod 998244353
ll l[N],r[N],cnt[N];
char a[N];
ll s[(N << 1) + 10],inv[(N << 1) + 10];
inline ll pow(ll a,ll b){
ll ans = 1;
while(b){
if(b & 1)ans = ans * a % mod;
a = a * a % mod;
b >>= 1;
}
return ans;
}
inline ll C(ll x,ll y){
if(x < y || x < 0 || y < 0)return 0;
return s[x] * inv[y] % mod * inv[x - y] % mod;
}
int main(){
scanf("%s",a + 1);
ll n = std::strlen(a + 1);
s[0] = 1;
for(int i = 1;i <= N << 1;++i)
s[i] = s[i - 1] * i % mod;
inv[N << 1] = pow(s[N << 1],mod - 2);
for(int i = (N << 1) - 1;i >= 0;--i)
inv[i] = (i + 1) * inv[i + 1] % mod;
l[0] = r[0] = cnt[0] = 0;
for(int i = 1;i <= n;++i){
l[i] = l[i - 1];
r[i] = r[i - 1];
cnt[i] = cnt[i - 1];
if(a[i] == '(')
l[i] ++ ;
if(a[i] == ')')
r[i] ++ ;
if(a[i] == '?')
cnt[i] ++ ;
}
ll ans = 0;
for(int i = 1;i <= n;++i){
ll li = l[i] - l[0];
ll ri = r[n] - r[i];
ll x = cnt[i] - cnt[0];
ll y = cnt[n] - cnt[i];
ans = (ans + li * C(x + y,ri + y - li) % mod + x * C(x + y - 1,ri + y - li - 1) % mod) % mod;
}
std::cout<<ans<<std::endl;
}