Counting Factorizations

任何一个正整数 \(m\) 都可以被唯一的分解为 \(p_1^{e_1} \cdot p_2^{e_2} \ldots p_k^{e_k}\) 的形式。将正整数 \(m\) 的唯一质数分解转化为一个长度为 \(2k\) 的 可重集合 记为 \(f(m)\)。

\[f(m)=\{p_1,e_1,p_2,e_2,p_3,e_3, \ldots ,p_k,e_k \}
\]

给定正整数 \(n\) 和一个长度为 \(2n\) 的可重集 \(A\)。求出满足 \(f(m) = A\) 的正整数 \(m\) 的个数。答案对 \(998\ 244\ 353\) 取模。

\(1≤n≤2022\)

\(1≤a_i≤10^6\)

题解:欧拉筛 + 组合计数 + \(DP\)

只有质数才能作为底数,也就是说我们要在\(2n\)个数中选择\(n\)个的不同的质数作为底数,多余\(n\)个的质数和非质数作为指数,设有\(s_1\)个非质数,每个非质数数量为\(b_i\),有\(s_2\)个质数,每个质数的数量为\(c_i\) ,我们在\(s_2\)个质数中选择n个质数作为底数也就是使对应的数量减\(1\),\(c_i':=c_i-1\),根据组合计数的原理我们得到答案为

\[\sum\frac{n!}{b_1!b_2!...b_{s_1!}c_1'c_2'...c_{s_2}'}
\]

实际上左半部分贡献是固定的\(\frac{n!}{b_1!b_2!...b_{s_1!}}\),我们只需求出\(\sum\frac{1}{c_1'c_2'...c_{s_2}'}\)即可,那么对于这部分贡献我们可以通过\(DP\)求出

状态表示:\(f[i][j]\):在前\(i\)个质数中选择\(j\)个作为底数的方案数 \(O(n^2)\)

状态属性:数量

状态计算:

  • 不选择第\(i\)个质数作为底数
\[f[i][j] = f[i][j] + f[i-1][j]*c[i]!,j<=i
\]
  • 选择第\(i\)个质数作为底数
\[f[i][j] = f[i][j] + f[i-1][j-1]*(c[i] - 1)!,j<=i
\]

状态初始:\(f[0][0]=1\)

答案呈现:从\(s_2\)个质数中选\(n\)个质数作为底数的方案数,\(f[s_2][n]\)

我们应该提前利用快速幂来预处理阶乘的逆元\(O(nlogn)\),同时利用欧拉筛提前预处理出\(1e6\)范围内的质数

#include <bits/stdc++.h>
#define Zeoy std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0)
#define debug(x) cerr << #x << '=' << x << endl
#define all(x) (x).begin(), (x).end()
#define rson id << 1 | 1
#define lson id << 1
#define int long long
#define mpk make_pair
#define endl '\n'
using namespace std;
typedef unsigned long long ULL;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 998244353;
const double eps = 1e-9;
const int N = 1e6 + 10, M = 5e3 + 10; int n;
int p[N], vis[N], idx;
int fact[M], inv[M], c[M];
int f[M][M];
unordered_map<int, int> uprime, prime; int qpow(int a, int b, int p)
{
int res = 1;
while (b)
{
if (b & 1)
res = res * a % p;
b >>= 1;
a = a * a % p;
}
return res % p;
} void get_primes(int n)
{
vis[1] = 1;
for (int i = 2; i <= n; ++i)
{
if (!vis[i])
p[++idx] = i;
for (int j = 1; j <= idx && p[j] * i <= n; ++j)
{
vis[p[j] * i] = 1;
if (i % p[j] == 0)
break;
}
}
} void solve()
{
cin >> n;
get_primes(1e6);
int tot = 0;
for (int i = 1; i <= 2 * n; ++i)
{
int x;
cin >> x;
if (!vis[x])
prime[x]++;
else
uprime[x]++;
}
fact[0] = inv[0] = 1;
for (int i = 1; i <= n; ++i)
{
fact[i] = fact[i - 1] * i % mod;
inv[i] = inv[i - 1] * qpow(i, mod - 2, mod) % mod;
}
int ans = fact[n];
for (auto [x, y] : uprime)
ans = ans * inv[y] % mod;
int cnt = 0;
for (auto [x, y] : prime)
c[++cnt] = y;
f[0][0] = 1;
for (int i = 1; i <= cnt; ++i)
{
for (int j = 0; j <= i; ++j)
f[i][j] = (f[i][j] % mod + f[i - 1][j] * inv[c[i]] % mod) % mod;
for (int j = 1; j <= i; ++j)
f[i][j] = (f[i][j] % mod + f[i - 1][j - 1] * inv[c[i] - 1] % mod) % mod;
}
cout << (ans % mod * f[cnt][n] % mod) % mod << endl;
}
signed main(void)
{
Zeoy;
int T = 1;
// cin >> T;
while (T--)
{
solve();
}
return 0;
}

Codeforces Round 856 (Div2)的更多相关文章

  1. A. Launch of Collider Codeforces Round #363 (Div2)

    A. Launch of Collider time limit per test 2 seconds memory limit per test 256 megabytes input standa ...

  2. Codeforces Round #539 div2

    Codeforces Round #539 div2 abstract I 离散化三连 sort(pos.begin(), pos.end()); pos.erase(unique(pos.begin ...

  3. 【前行】◇第3站◇ Codeforces Round #512 Div2

    [第3站]Codeforces Round #512 Div2 第三题莫名卡半天……一堆细节没处理,改一个发现还有一个……然后就炸了,罚了一啪啦时间 Rating又掉了……但是没什么,比上一次好多了: ...

  4. Codeforces Round#320 Div2 解题报告

    Codeforces Round#320 Div2 先做个标题党,骗骗访问量,结束后再来写咯. codeforces 579A Raising Bacteria codeforces 579B Fin ...

  5. Codeforces Round #564(div2)

    Codeforces Round #564(div2) 本来以为是送分场,结果成了送命场. 菜是原罪 A SB题,上来读不懂题就交WA了一发,代码就不粘了 B 简单构造 很明显,\(n*n\)的矩阵可 ...

  6. Codeforces Round #361 div2

    ProblemA(Codeforces Round 689A): 题意: 给一个手势, 问这个手势是否是唯一. 思路: 暴力, 模拟将这个手势上下左右移动一次看是否还在键盘上即可. 代码: #incl ...

  7. codeforces 572(Div2)A、B、C、D1、D2、E

    Cdoeforces 572(Div2)A.B.C.D1.D2.E 传送门:https://codeforces.com/contest/1189 A.题意: 给你一串长为n的字符串,要求你将其切割为 ...

  8. Codeforces Round #626 Div2 D,E

    比赛链接: Codeforces Round #626 (Div. 2, based on Moscow Open Olympiad in Informatics) D.Present 题意: 给定大 ...

  9. codeforces round 472(DIV2)D Riverside Curio题解(思维题)

    题目传送门:http://codeforces.com/contest/957/problem/D 题意大致是这样的:有一个水池,每天都有一个水位(一个整数).每天都会在这一天的水位上划线(如果这个水 ...

  10. Codeforces Round #626 Div2 D. Present(位掩码,二分)

    题目链接:https://codeforces.com/contest/1323/problem/D 题意:给了大小为4e5的数组a,其中1<=ai<=1e7.求所有点对和的异或和,即: ...

随机推荐

  1. 使用 Microsoft.Extensions.ServiceDiscovery 进行服务发现并调用

    简介 在现代微服务架构中,服务发现(Service Discovery)是一项关键功能.它允许微服务动态地找到彼此,而无需依赖硬编码的地址.以前如果你搜 .NET Service Discovery, ...

  2. 画流程图、状态图、时序图、甘特图的JS库-mermaid-js

    参考地址:https://github.com/mermaid-js/mermaid 原生使用方式: <!DOCTYPE html> <html> <head> & ...

  3. QT6窗口系统之QT底层窗口QWindow:QT框架中哪些常见窗口是基于QWindow的? 如何实现QT框架栅格窗口?如何实现QT框架OpenGL窗口?

    QT6窗口系统之QT底层窗口QWindow:QT框架中哪些常见窗口是基于QWindow的? 如何实现QT框架栅格窗口?如何实现QT框架OpenGL窗口? 简介 本文介绍了QT6窗口系统中的QT底层窗口 ...

  4. SimpleRAG-v1.0.3:增加文件对话功能

    Kimi上有一个功能,就是增加文件之后对话,比如我有如下一个私有文档: 会议主题:<如何使用C#提升工作效率> 参会人员:张三.李四.王五 时间:2024.9.26 14:00-16:00 ...

  5. 三,MyBatis-Plus 的各种查询的“超详细说明”,比如(等值查询,范围查询,模糊查询...)

    三,MyBatis-Plus 的各种查询的"超详细说明",比如(等值查询,范围查询,模糊查询...) @ 目录 三,MyBatis-Plus 的各种查询的"超详细说明&q ...

  6. Windows右下角时间显示到秒(改注册表)

    ​ 事件起因: 由于京东秒杀,要准点抢购,于是想着能不能把Windows右下角的时间显示到秒,于是在网上查了一下,修改注册表即可 解决办法: 新建一个 ShowSecondsInSystemClock ...

  7. Android 12 关机重启流程

    1. 关机流程 Android上层触发关机的入口很多,但最终几乎都是调用ShutdownThread.shutdown来实现.如下是一些常见的调用关机的点: StatusBarManagerServi ...

  8. PCI-5565反射内存卡

    PCI-5565反射内存卡是一种用于实时网络的硬件设备.它基于反射内存网的原理,通过光纤连接多台计算机,形成网络节点,并且每个节点上的网络内存卡存储着其他节点的共享数据拷贝.该反射内存卡可以插在多种总 ...

  9. flink同步MySQL数据的时候出现内存溢出

    flink同步MySQL数据的时候出现内存溢出 背景:需要将1000w的某类型数据同步到别的数据源里面,使用公司的大数据平台可以很快处理完毕,而且使用的内存只有很少很少量(公司的大数据平台的底层是fl ...

  10. 基于 KubeKey 扩容 Kubernetes v1.24 Worker 节点实战

    前言 知识点 定级:入门级 KubeKey 扩容 Worker 节点 openEuler 操作系统的基本配置 Kubernets 基本命令 实战服务器配置(架构 1:1 复刻小规模生产环境,配置略有不 ...