codeforces1622D Shuffle(组合/容斥)

题目链接:codeforces 1622D
题目思路:

暴力枚举区间 [l, r],每次考虑把边界上的 1 1 1 放在中间的方案数。用预处理的方法求组合数。

参考代码:
#include <iostream>
#include <vector>
#include <string>
using namespace std;
typedef long long ll;
const int N =5000+10;
const int mod = 998244353;
ll n, k;
string s;
ll fac[N], inv_fac[N];
ll a[N];
ll qpow(ll a, ll b) {
    ll res = 1;
    a %= mod;
    while (b > 0) {
        if (b & 1) {
            res = res * a % mod;
        }
        a = a * a % mod;
        b >>= 1;
    }
    return res;
}
ll inv(ll x, ll p) {
    return qpow(x, p-2);
}
void prework() {
    fac[0] = inv_fac[0] = 1;
    for (int i = 1; i <= 5000; i++) {
        fac[i] = fac[i-1] * i % mod;
        inv_fac[i] = inv_fac[i-1] * inv(i, mod) % mod;
    }
}
ll C(ll n, ll m) {
    if (n < m || m < 0) return 0;
    return fac[n] * inv_fac[m] % mod * inv_fac[n-m] % mod;
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
    cin >> n >> k >> s;
    prework();
    for (int i = 0; i < n; i++) a[i] = s[i] - '0';
    vector<int> pre(n+1);
    for (int i = 0; i < n; i++) {
        pre[i+1] = pre[i] + a[i];
    }
    ll ans = 1;
    if (pre[n] >= k) {
        for (int i = 0; i < n; i++) {
            for (int j = i + 1; j < n; j++) {
                int cnt = pre[j+1] - pre[i];
                if (cnt <= k) {
                    cnt -= (a[i] ^ 1) + (a[j] ^ 1);
                    int len = j - i - 1;
                    ans += C(len, cnt);
                    ans %= mod;
                }
            }
        }
    }
    cout << ans << endl;
    return 0;
}
上一篇:数据结构+DP 笛卡尔树 SP3734题解


下一篇:【方向盘】使用IDEA的60+个快捷键分享给你,权为了提效(IDEA导航篇)