【计数DP】CF1794D 痛定思痛。 2024-02-21 12:04 49阅读 0赞 [Problem - D - Codeforces][] 题意 ![06493c1d861a49e6995818c716958851.png][] 思路 解法大方向对了,但是还是不会做,原因是组合数不知道怎么求 首先需要注意到一些东西: 1.底数一定是质数 2.质数个数 < n 一定无解 3.哪些质数作为底数是不确定的 4.n <= 2022 那么我们其实可以把做法大致猜出来 根据第4点,应该是个二维的dp,且状态的设计感觉非常唯一: 设 dp\[i\]\[j\] 表示前 i 个数,已经选了 j 个数作为底数的方案数 然后就是考虑转移,这种计数类的dp在转移的时候都是考虑多一格会多出多少贡献,贡献一般由组合数求出 问题就是出在这里,我不知道怎么求组合数,一心想着对于指数求可重集排列,但是这么多的指数的个数是很难维护的 其实应该考虑分配,算出组合就行了,不用去考虑排列 设多出来那一格的数为 x, 它的个数为 y 那就是考虑把这 y 个 x 分配到 指数中,指数中还剩余多少个空位呢 前缀已经选了 j 个底数,设前缀的个数和为 sum,那么前缀有 sum - j 个数作为指数 所以还剩下 n - (sum - j) 个位置,也就是说,在 n - (sum - j) 个位置中选 y 个位置,那就是 C(n - (sum - j), y) 如果作为底数也是同样的道理 对 x 作为指数还是底数讨论一下即可 Code: #include <bits/stdc++.h> #define int long long constexpr int N = 1e6 + 10; constexpr int mod = 998244353; constexpr int Inf = 0x3f3f3f3f; int n, x; int len = 0; int Fac[N]; int inv[N]; int vis[N], prime[N]; int qpow(int a, int b) { int res = 1; while(b) { if (b & 1) res = (res * a) % mod; a = (a * a) % mod; b >>= 1; } return res; } int C(int n, int m) { if (n < 0 || m < 0 || n < m) return 0; return Fac[n] * inv[m] % mod * inv[n - m] % mod; } void Fac_init() { Fac[0] = 1; for (int i = 1; i < N; i ++) { Fac[i] = (Fac[i - 1] * i) % mod; } inv[N - 1] = qpow(Fac[N - 1], mod - 2); for (int i = N - 2; i >= 0; i --) { inv[i] = inv[i + 1] * (i + 1) % mod; } } void P_init(int n) { vis[1] = 1; for (int i = 2; i <= n; i ++) { if (!vis[i]) prime[++len] = i; for (int j = 1; i <= n / prime[j]; j ++) { vis[i * prime[j]] = 1; if (i % prime[j] == 0) break; } } } void solve() { std::cin >> n; std::map<int, int> mp; for (int i = 1; i <= 2 * n; i ++) { std::cin >> x; mp[x] += 1; } int sum = 0; std::vector<int> dp(n + 1, 0); dp[0] = 1; for (auto [x, y] : mp) { std::vector<int> ndp(n + 1, 0); for (int j = 0; j <= n; j ++) { ndp[j] += dp[j] * C(n - (sum - j), y) % mod; ndp[j] %= mod; if (j >= 1 && !vis[x]) { ndp[j] += dp[j - 1] * C(n - (sum - j + 1), y - 1) % mod; ndp[j] %= mod; } } dp.swap(ndp); sum += y; sum %= mod; } std::cout << dp[n] % mod << "\n"; } signed main() { std::ios::sync_with_stdio(false); std::cin.tie(nullptr); int t = 1; Fac_init(); P_init(1e6); while (t--) { solve(); } return 0; } [Problem - D - Codeforces]: https://codeforces.com/contest/1794/problem/D [06493c1d861a49e6995818c716958851.png]: https://image.dandelioncloud.cn/pgy_files/images/2024/02/21/6b11376ece854e45a919c22836cdc813.png
相关 【计数DP】CF1794D [Problem - D - Codeforces][] 题意 ![06493c1d861a49e6995818c716958851.png][] 思路 解法大方向对了 痛定思痛。/ 2024年02月21日 12:04/ 0 赞/ 50 阅读
相关 计数问题 题目描述 试计算在区间 1 到 n 的所有整数中,数字x(0≤x≤9) 共出现了多少次?例如,在 1到11中,即在 1,2,3,4,5,6,7,8,9,10,11中,数字 喜欢ヅ旅行/ 2022年11月28日 13:36/ 0 赞/ 123 阅读
相关 【基础练习】【树形DP】codevs1794 修剪花卉题解 题目描述 Description ZZ对数学饱有兴趣,并且是个勤奋好学的学生,总是在课后留在教室向老师请教一些问题。 一天他早晨骑车去上课,路上见到一个老伯正在修剪花花草草 旧城等待,/ 2022年08月09日 17:38/ 0 赞/ 126 阅读
相关 计数排序 计数排序,他的主要目的是对整数排序并且会比普通的排序算法性能更好。 1. 初始化一个计数数组,大小是输入数组中的最大的数。 2. 遍历输入数组,遇到一个数 布满荆棘的人生/ 2022年07月14日 01:26/ 0 赞/ 211 阅读
相关 计数(dp 描述:计算从1到n中,每个数字(0到9)出现的次数 其中sum[j]和dp[i]表示:数字i中 j 的个数;比如sum[1]和dp[5]就可以表示:5中1的 梦里梦外;/ 2022年06月18日 00:29/ 0 赞/ 195 阅读
相关 计数 题目描述 统计数组 arr 中值等于 item 的元素出现的次数 示例1 输入 [1, 2, 4, 4, 3, 4, 3], 4 输出 桃扇骨/ 2022年06月05日 06:41/ 0 赞/ 225 阅读
相关 计数排序 计数排序 算法描述:是一种通过计数来达到排序的方法。 ![20180326152550965][] 1.选出数组的最大值k,创建一个k+1长度的数组coun 素颜马尾好姑娘i/ 2022年05月28日 00:20/ 0 赞/ 216 阅读
相关 计数质数 题目描述 统计所有小于非负整数 n 的质数的数量。 示例: 输入: 10 输出: 4 解释: 小于 10 的质数一共有 4 个, 它们是 2, 我会带着你远行/ 2022年02月25日 06:10/ 0 赞/ 240 阅读
相关 计数排序 / 计数排序:统计小于等于该元素值的元素的个数i,于是该元素就放在目标数组的索引i位(i≥0)。 计数排序基于一个假设,待排序数列的 ゝ一纸荒年。/ 2021年12月18日 05:07/ 0 赞/ 306 阅读
相关 计数排序 计数排序: 假设n个输入元素中的每一个都是在0~区间内的一个整数,其中k为某个整数。当k=O(n)是,排序时间为O(n). 基本思想:对每个输入元素x,确定小于x元素的 淡淡的烟草味﹌/ 2021年09月23日 03:22/ 0 赞/ 397 阅读
还没有评论,来说两句吧...