CF1240D1 (组合数)

题目大意:

长度为 n ( ≤ 2000 ) n(\le 2000) n(2000)的字符串,字符串包含 ′ ( ′ '(' (, ′ ? ′ '?' ?, ′ ) ′ ')' ) ′ ? ′ '?' ?可以是 ′ ( ′ '(' (或者 ′ ) ′ ')' ),对于一个不含 ′ ? ′ '?' ?的序列,计算其子序列的最大深度,询问不同方案下最大深度和。

解题思路:

  • p r e i , j pre_{i,j} prei,j 1 ∼ i 1\sim i 1i的前缀字符,有 j j j ′ ( ′ '(' (,这个可以用组合数来算,同理算 s u f i , j suf_{i,j} sufi,j
  • a n s = ∑ i = 1 n ∑ j = 1 n p r e i , j ∗ s u f i + 1 , j ∗ j ans = \sum_{i=1}^n\sum_{j=1}^n pre_{i,j}*suf_{i+1,j}*j ans=i=1nj=1nprei,jsufi+1,jj

AC代码:

#include <bits/stdc++.h>
#define ft first
#define sd second
#define pb push_back
#define IOS ios::sync_with_stdio(false), cin.tie(0), cout.tie(0) //不能跟puts混用
#define seteps(N) fixed << setprecision(N)
#define endl "\n"
const int maxn = 2e3 + 10;
using namespace std;
typedef long long ll;
typedef double db;
typedef pair<int, int> pii;
const int mod = 998244353;
char s[maxn];
int n, psum0[maxn], psum1[maxn], ssum0[maxn], ssum1[maxn];
ll pre[maxn][maxn], suf[maxn][maxn], fac[maxn], rfac[maxn];
ll qpow(ll a, ll b, ll mod) {
   ll res = 1;
   while (b) {
       if (b & 1) res = res * a % mod;
       a = a * a % mod;
       b >>= 1;
   }
   return res;
}
void init() {
    fac[0] = 1;
    for (int i = 1; i < maxn; i++) fac[i] = fac[i - 1] * i % mod;
    rfac[maxn - 1] = qpow(fac[maxn - 1], mod - 2, mod);
    for (int i = maxn - 2; i >= 0; i--) rfac[i] = rfac[i + 1] * (i + 1) % mod;
}
ll C(ll n, ll m) {
    if (n < m) return 0;
    return fac[n] * rfac[n - m] % mod * rfac[m] % mod;
}
int main() {
    IOS;
    init();
    cin >> s + 1;
    n = strlen(s + 1);
    for (int i = 1; i <= n; i++) psum0[i] = psum0[i - 1] + (s[i] == '?');
    for (int i = 1; i <= n; i++) psum1[i] = psum1[i - 1] + (s[i] == '(');
    for (int i = n; i >= 1; i--) ssum0[i] = ssum0[i + 1] + (s[i] == '?');
    for (int i = n; i >= 1; i--) ssum1[i] = ssum1[i + 1] + (s[i] == ')');
    
    for (int i = 1; i <= n; i++) 
        for (int j = psum1[i]; j <= psum0[i] + psum1[i]; j++) {
            pre[i][j] = C(psum0[i], j - psum1[i]);
        }
    for (int i = 1; i <= n; i++)
        for (int j = ssum1[i]; j <= ssum0[i] + ssum1[i]; j++) {
            suf[i][j] = C(ssum0[i], j - ssum1[i]);
        }    
    ll ans = 0;
    for (int i = 1; i <= n - 1; i++)
        for (int j = 1; j <= n; j++)
            ans = (ans + pre[i][j] * suf[i + 1][j] % mod * j % mod) % mod;
    cout << ans << endl;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值