CF1158F Density of subarrays

news/2025/1/11 16:31:39/文章来源:https://www.cnblogs.com/Pengzt/p/18665821

Density of subarrays

题目链接。

Problem

我们定义一个“\(c\) 序列”为序列里的数都是 \([1, c]\) 的序列。定义一个 \(c\) 序列的“密度”为最大的 \(p\),使得任意长度为 \(p\) 的序列(总共 \(c^p\) 个)都是它的子序列。

给定一个长度为 \(n\) 的“\(c\) 序列”,对 \(p \in [0, n]\),求该序列有多少个子序列的密度为 \(p\),答案对 \(998244353\) 取模。

数据范围:\(n, m \le 3000\)

Sol

感觉这道题难点在于知道复杂度!如果这个题被扔到 OI 里,给两个部分分是不是就完全没难度了。

先考虑一下如何判定一个序列的密度。这是一个很简单的贪心。假如之前已经匹配到 \(i\),由于是任意长度为 \(p\) 的序列,所以肯定是尽量往后找。即找到第一个使得 \([i, j]\) 中出现 \(1 \sim c\) 所有数的位置 \(j\),然后让答案增加一,继续进行刚才的操作,无法再找到下一个 \(j\) 时结束。于是就有一个很简单的 DP:定义 \(f_{i, j}\) 表示填了 \(i\) 个数,密度为 \(j\) 的方案数。则有转移 \(f_{i, j} = \sum\limits_{k < i}f_{k, j - 1} \cdot w(k + 1, i)\),其中 \(w(l, r)\) 表示 \(a_l, a_{l + 1}, \dots, a_r\) 中有多少个子序列满足 \(1 \sim n\) 中的数都出现了至少一次。\(w(i, j)\) 是好算的,可以 \(\mathcal{O}(n^2)\) 预处理出。然后这就得到了一个很简单的 \(\mathcal{O}(n^3)\) 的做法。然后发现这道题 \(n \le 3000\) 还开了六秒,肯定就不是 \(\mathcal{O}(n^2)\) 的。仔细分析一下刚才做法的复杂度。不难发现,当 \(p > \frac nc\) 时,答案一定为 \(0\),所以刚才 DP 的第二维是 \(\mathcal{O}(\frac nc)\) 的,于是这个 DP 就变成了 \(\mathcal{O}(\frac{n^3}{c})\) 了。于是发现只有这个 \(c\) 比较小的时候才会跑的比较慢,想一下 \(c\) 比较小咋做。

不难得出一个暴力 DP:\(g_{i, j, S}\) 表示填了 \(i\) 个数,当前密度为 \(p\)\(1 \sim c\) 中的数填过的集合为 \(S\) 的方案数。转移是很简单的,枚举 \(a_i\) 选不选就行了。然后这个东西的时间复杂度是 \(\mathcal{O}(n\cdot \frac nc \cdot 2^c)\) 的。当 \(\frac{n^22^c}{c} = \frac{n^3}{c}\) 时,\(c = \log_2 n\)。所以 \(c\)\(10\) 左右比较好。最后的时间复杂度变为 \(\mathcal{O}(\frac{n^3}{\log n})\)

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;elsecnt++;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;elsecnt++;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;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/867812.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

md学习DAY1

Markdown学习DAY1 标题 三级标题 四级标题 字体 粗体hello,world! 斜体hello,world! 斜体加粗hello,world! 废除hello,world! 引用选择疯狂包,成为包上包分割线图片超链接 点击跳转到疯狂包子的博客 列表A B CA B C表格姓名 性别 出生代码 public

CheeseTools:红队内网横向

免责声明 仅限用于技术研究和获得正式授权的攻防项目,请使用者遵守《中华人民共和国网络安全法》,切勿用于任何非法活动,若将工具做其他用途,由使用者承担全部法律及连带责任,作者及发布者不承担任何法律连带责任项目介绍 这个库是基于已经存在的MiscTool制作的,所以非常…

2025 最新中国铁路路线地图 All In One

2025 最新中国铁路路线地图 All In One 中国铁路 12306 网站2025 最新中国铁路路线地图 All In One中国铁路 12306 网站高铁线路图中国高速铁路线路图 / 中国高铁线路规划图https://crh.gaotie.cn/ demosC3035 复 上海南 -> 亳州南 07:45 ~ 12:34 (04:49) 当日到达站序 站名…

JAVA-Day 12:方法的定义和调用

方法的定义和调用 方法定义的格式: public static void 方法名(){方法体(就是打包起来的代码)} 方法调用的格式: 方法名(); 定义调用一个方法用于个人介绍 public static void main(String[] args){myself(); } public static void myself(){System.out.println("小王同学…

PC电脑屏幕实时翻译工具-Translumo

点击上方蓝字关注我 前言 Translumo是基于.Net开发的、开源屏幕翻译器软件,它可以实时检测并翻译屏幕上所选区域中出现的文本,可检测视频中的字幕或图片中出现文字等 安装环境 [名称]:Translumo [大小]:500MB [版本]:0.9.6 [语言]:简体中文 [安装环境]:Windows 界面使用…

Text1-综合练习5

Text-综合练习5 产生十个1-100之间的随机数存入数组 求和 求平均数 找出有几个数字比平均值小 Random number1=new Random();Scanner number2=new Scanner(System.in);System.out.println("请输入要产生随机数的个数:");int n=number2.nextInt();int arr[]=new int […

Text1-综合练习6

Text-综合练习6 键盘录入n个数字,倒放他们的顺序 例如:输入1 2 3 4 5,输出5 4 3 2 1 Scanner EX=new Scanner(System.in);String arr[]=new String[100];String temp;int count=0;System.out.println("请输入要交换的数字:,以空格结束");for (int i = 0; i < 1…

Text1-综合练习2

Text-综合练习2 键盘录入一个大于2的整数,求它的平方根 结果省去小数部分保留整数 Scanner st=new Scanner(System.in);System.out.println("请输入一个大于2的整数:");int number1=st.nextInt();for(int i=1;i<number1;i++){//从1开始查找一直到number1的值int n…

Text1-综合练习1

Text1-综合练习1 逢七过 游戏规则:从任意一个数字开始报数 当你要报的数字包含七或者是七的倍数时都要说过 需求:使用程序在控制台打印出1-100之间满足逢七过规则的数 for(int i=1;i<=100;i++){if(i/10%10==7||i%10==7||i%7==0){//判断十位、个位有没有七,这个数是否能被七…

ciscn_2019_n_8 1

checksec一下能发现开了很多保护,吓人一跳,但其实我们分析一下发现只要var[13]为17就可以了if ( *(_QWORD *)&var[13] )#判断var[13]开始的8字节(_QWORD表示64位,即8字节)内存区域是否非零。*(_QWORD *)&var[13]是将var[13]的地址转换为_QWORD(64位整数)指针,然…

Unity URP Shader Graph 实现复古电视机效果

想到一出实现一出的复古电视机效果实现。复古电视机效果显示展示:使用素材 一张纹理需要放映的图片,一张遮罩贴图,一个电视机模型。UV使用Spherize模拟电视机球状显示屏。 扫描线A效果扫描线B效果像素化/随机UV偏移屏幕做旧效果边缘变暗效果屏幕黑边效果 自制一张合适的贴图…

终于决定:把自己家的能源管理系统开源了!

决定了很久把自己公司的能管平台开源了,部分功能和bug正在修复中。 欢迎star 欢迎轻拍 地址:https://gitee.com/ustcyc/zhitan-ems 介绍 通过物联网技术,采集企业水、电、气、热等能耗数据,帮企业建立能源管理体系,找到跑冒滴漏,从而为企业节能提供依据。 进一步为企业实…