$ T1 $
感覺沒有藍,只有中綠左右。
賽時寫了正解,漏了個 $ + $ 號,寄了,然後逆元處理了 $ inv $,但是不知道為什麼寫的是快速冪,於是就 T 了。
考慮列舉兩端改變,中間隨便的區間 $ [i,j] $,然後亂搞即可。
$ \color{black}{zzzcr} $ 有一個 $ O(n) $ 的做法是考慮雙指標,然後對於有交的區間減去中間重疊的部分。
實際上賽時這題一眼是想到雙指標的,但是沒有仔細想,因為看到 $ 1\le n \le 5000 $,覺得正解大概是 $ O(n^2) $ 的,就沒有繼續調。
不過 $ O(n) $ 的演算法框架,大體是想到了的,差不多到減去中間重疊的部分。
唉,太菜了。
//AsahinaMafuyu
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 5010, MOD = 998244353;
int n, k;
char a[N];
int res, f[N][N];
int C[N][N];
//設f[i][j]表示區間[i, j]改變的方案數(i, j改變,其他隨便)
int fac[N], inv[N];
int qp(int a, int b)
{
int res = 1;
while (b)
{
if (b & 1) (res *= a) %= MOD;
(a *= a) %= MOD;
b >>= 1;
}
return res;
}
int C_(int n, int m)
{
if (n < 0 || m < 0) return 0;
return C[n][m];
}
signed main()
{
cin >> n >> k;
for (int i = 1; i <= n; i ++ ) cin >> a[i];
C[0][0] = 1;
for (int i = 1; i <= n; i ++ )
{
C[i][0] = 1;
for (int j = 1; j <= i; j ++ )
(C[i][j] = C[i - 1][j - 1] + C[i - 1][j]) %= MOD;
}
fac[0] = 1, a[0] = '0';
for (int i = 1; i <= n; i ++ ) (fac[i] = fac[i - 1] * i) %= MOD;
inv[n] = qp(fac[n], MOD - 2);
for (int i = n - 1; ~i; i -- ) inv[i] = inv[i + 1] * (i + 1) % MOD;
int sum = 0;
for (int i = 1; i <= n; i ++ )
{
int j, s = 0, s0 = 0, s1 = 0;
if (a[i] == '1') s ++ ;
sum += s;
if (a[i] == '1') s1 ++ , s0 -- ;
else s0 ++ , s1 -- ;
for (j = i + 1; j <= n; j ++ )
{
s += a[j] - '0';
if (s > k) break;
s0 += '1' - a[j], s1 += a[j] - '0';
if (a[j] == '1') s0 -- ;
else s1 -- ;
(f[i][j] += C_(s0 + s1, s1)) %= MOD;
if (a[j] == '1') s0 ++ ;
else s1 ++ ;
}
if (s < k && j <= n)
for (int j = i + 1; j <= n; j ++ )
f[i][j] = 0;
}
int res = 0;
for (int i = 1; i <= n; i ++ )
for (int j = i + 1; j <= n; j ++ )
(res += f[i][j]) %= MOD;
if (sum < k) res = 0;
cout << (res + 1) % MOD << '\n';
return 0;
}
$ T2, T3 $ 再說吧。