CF1158F Density of subarrays
Density of subarrays
题目链接。
Problem
我们定义一个“
给定一个长度为
数据范围:
Sol
感觉这道题难点在于知道复杂度!如果这个题被扔到 OI 里,给两个部分分是不是就完全没难度了。
先考虑一下如何判定一个序列的密度。这是一个很简单的贪心。假如之前已经匹配到
不难得出一个暴力 DP:
Code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
#define fi first
#define se second
mt19937_64 eng(time(0) ^ clock());
template<typename T>
T rnd(T l, T r) { return eng() % (r - l + 1) + l; }
const int P = 998244353;
ll QPow(ll a, ll b) {
ll res = 1;
for (; b; a = a * a % P, b >>= 1)
if (b & 1)
res = res * a % P;
return res;
}
int n, c;
int a[3005];
namespace SolveB {
int cnt, buc[3005];
ll g[3005][3005], h[3005], pw2[3005], ipw1[3005], ipw2[3005];
unsigned long long f[3005][3005];
void Work() {
pw2[0] = 1;
for (int i = 1; i <= n; i++)
pw2[i] = pw2[i - 1] * 2 % P;
for (int i = 0; i <= n; i++)
ipw1[i] = QPow((pw2[i] + P - 1) % P, P - 2),
ipw2[i] = QPow(pw2[i], P - 2);
for (int l = 1; l <= n; l++) {
memset(buc, 0, sizeof (buc));
ll res = 1;
for (int r = l; r <= n; r++) {
if (buc[a[r]])
res = res * ipw1[buc[a[r]]] % P;
else
cnt++;
buc[a[r]]++;
res = res * (pw2[buc[a[r]]] + P - 1) % P;
if (cnt == c)
g[l][r] = res * ipw1[buc[a[r]]] % P;
}
cnt = 0;
}
memset(buc, 0, sizeof (buc));
cnt = 0;
ll all = 1, res = 1;
h[n + 1] = 1;
for (int i = n; i; i--) {
all = all * ipw2[buc[a[i]]] % P;
if (buc[a[i]])
res = res * ipw1[buc[a[i]]] % P;
else
cnt++;
buc[a[i]]++;
all = all * pw2[buc[a[i]]] % P;
res = res * (pw2[buc[a[i]]] + P - 1) % P;
h[i] = (all + P - (cnt == c ? res : 0)) % P;
}
f[0][0] = 1;
for (int i = 1; i * c <= n; i++)
for (int j = c * i; j <= n; j++) {
for (int k = (i - 1) * c; k <= n && g[k + 1][j]; k++) {
f[i][j] += f[i - 1][k] * g[k + 1][j];
if (!(k & 15))
f[i][j] %= P;
}
f[i][j] %= P;
}
for (int i = 0; i <= n; i++) {
ll ans = 0;
for (int j = c * i; j <= n; j++)
(ans += f[i][j] * h[j + 1]) %= P;
if (i * c > n)
ans = i == 0;
printf("%lld%c", ans - (i == 0), " \n"[i == n]);
}
}
}
namespace SolveS {
int f[2][3005][1 << 10];
void Work() {
for (int i = 1; i <= n; i++)
a[i]--;
f[0][0][0] = 1;
for (int i = 0; i < n; i++) {
int o = i & 1;
for (int j = 0; j * c <= i; j++)
for (int S = 0; S < (1 << c); S++) {
(f[o ^ 1][j][S] += f[o][j][S]) %= P;
if ((S | (1 << a[i + 1])) == (1 << c) - 1)
(f[o ^ 1][j + 1][0] += f[o][j][S]) %= P;
else
(f[o ^ 1][j][S | (1 << a[i + 1])] += f[o][j][S]) %= P;
}
for (int j = 0; j * c <= i; j++)
for (int S = 0; S < (1 << c); S++)
f[o][j][S] = 0;
}
for (int i = 0; i <= n; i++) {
int ans = 0;
for (int S = 0; S < (1 << c); S++)
(ans += f[n & 1][i][S]) %= P;
printf("%d%c", (ans + P - (i == 0)) % P, " \n"[i == n]);
}
}
}
int main() {
scanf("%d%d", &n, &c);
for (int i = 1; i <= n; i++)
scanf("%d", a + i);
if (c > 10)
return SolveB::Work(), 0;
SolveS::Work();
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
2023-01-11 ABC284E Count Simple Paths 题解
2023-01-11 ABC284D Happy New Year 2023 题解