题目链接: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;
}