\(\mathscr{Description}\)

  对于 \(r=0,1,\cdots,n-1\), 设 \(\{1,2,\cdots,nm\}\) 中有 \(f_r\) 个子集满足子集内元素之和 \(\bmod n=r\), 求出

\[\sum_{r=0}^{n-1}f_r^2\bmod 998244353.
\]

  \(n,m\le10^{18}\).

\(\mathscr{Solution}\)

  我们知道 \(f\) 的 GF:

\[F(x)=\left(\prod_{i=0}^{n-1}(1+x^i)\right)^m\bmod (x^n-1).
\]

于是我们需要用 \(\omega_n\) 对 \(F\) 做 DFT. 不妨设 \(\hat{f_k}=\operatorname{DFT}(\boldsymbol f)_k\), 那么

\[\hat{f_k}=\left(\prod_{i=0}^{n-1}(1+\omega_n^{ik})\right)^m.
\]

  看过 3B1B 的视频, 我们已知了对乘积式 \(\prod_{i=0}^{n-1}(1+\omega_n^i)\) 的处理技巧:

  注意到 \(1-z^n=0\Leftrightarrow z=\omega_n^k\), 那么 \(1-z^n=\prod_{i=0}^{n-1}(z-\omega_n^i)\). 代入 \(z=-1\), 观察左右, 我们有 \(\prod_{i=0}^{n-1}(1+\omega_n^i)=2[2\nmid n]\).

指标乘上常数 \(k\), 无非让 \(\omega_n\) 转圈圈的速度发生了一些变化. 令 \(d=\gcd(k,n)\), 容易得到

\[\hat{f_k}=[2\nmid (n/d)]2^{dm}.
\]

  答案应当为 \(\boldsymbol f^2\), 也即是 \(\sum_{i=0}^{n-1}f_i^2\). 注意到 \(\gcd(k,n)=\gcd(n-k,n)\), 于是 \(f_i=f_{n-i}\), 所以只需要求

\[\sum_{i=0}^{n-1}f_if_{-i\bmod n}=[x^0]F^2(x).
\]

如果能算 \(\hat{\boldsymbol f}\), 我们就能立马得到 \(\operatorname{DFT}(F^2)\), 接下来只需要提取 IDFT 矩阵的第一行 (带上 \(\frac{1}{n}\) 的系数) 与 \(F^2\) 的 DFT 向量做点乘就能得到答案.

  如何算 \(\hat{\boldsymbol f}\)? 将 \(n\) 素因数分解, 暴力枚举 \(d\) 算贡献即可. 使用 Pollard-Rho, 动态维护 \(\varphi(n/d)\), 预处理 \(2\) 的光速幂, 可以做到 \(\mathcal O(\sqrt P+Td(n))\), 其中 \(P=998244353\), \(d(n)\) 为 \(n\) 的因子个数 (其自然比 Pollard-Rho 的 \(n^{1/4}\) 高阶).

\(\mathscr{Code}\)

/*+Rainybunny+*/

// #include <bits/stdc++.h>
#include <bits/extc++.h> #define rep(i, l, r) for (int i = l, rep##i = r; i <= rep##i; ++i)
#define per(i, r, l) for (int i = r, per##i = l; i >= per##i; --i) typedef long long LL;
#define fi first
#define se second const int MOD = 998244353;
LL n, m;
__gnu_pbds::gp_hash_table<LL, int> fct; namespace Factor { inline LL add(LL u, const LL v, const LL m) {
return (u += v) < m ? u : u - m;
} inline LL mul(const LL u, const LL v, const LL m) {
return __int128(u) * v % m;
} inline LL mpow(LL u, LL v, LL m) {
LL ret = 1;
for (; v; u = mul(u, u, m), v >>= 1) ret = mul(ret, v & 1 ? u : 1, m);
return ret;
} inline LL gcd(const LL u, const LL v) { return v ? gcd(v, u % v) : u; } inline LL labs(const LL u) { return u < 0 ? -u : u; } inline bool millerRabin(const LL x, const LL b) {
LL k = x - 1; while (!(k & 1)) k >>= 1;
static LL pwr[70]; pwr[0] = 1, pwr[1] = mpow(b, k, x);
while (k != x - 1) {
pwr[pwr[0] + 1] = mul(pwr[pwr[0]], pwr[pwr[0]], x);
++pwr[0], k <<= 1;
}
per (i, pwr[0], 1) {
if (pwr[i] != 1 && pwr[i] != x - 1) return false;
if (pwr[i] == x - 1) return true;
}
return true;
} inline bool isprime(const LL x) {
if (x == 2 || x == 3 || x == 5 || x == 7 || x == 11) return true;
if (x == 61 || x == 127) return true;
if (!(x % 2) || !(x % 3) || !(x % 5) || !(x % 7) || !(x % 11))return false;
if (!(x % 61) || !(x % 127)) return false;
return millerRabin(x, 2) && millerRabin(x, 61) && millerRabin(x, 127);
} inline LL pollardRho(const LL x) {
static std::mt19937 emt(time(0) ^ 20120712);
for (LL a = emt() % (x - 1) + 1, len = 1, st = 0, ed = 0; ;
len <<= 1, st = ed) {
LL prd = 1;
rep (stp, 1, len) {
prd = mul(prd, labs(st - (ed = add(mul(ed, ed, x), a, x))), x);
if (!(stp & 127) && gcd(prd, x) > 1) return gcd(prd, x);
}
if (gcd(prd, x) > 1) return gcd(prd, x);
}
} inline void factor(LL x, __gnu_pbds::gp_hash_table<LL, int>& res,
const int k = 1) {
if (x == 1) return ;
if (isprime(x)) return void(res[x] += k);
LL d = pollardRho(x); int cnt = 0;
while (!(x % d)) x /= d, ++cnt;
factor(x, res, k), factor(d, res, k * cnt);
} } // namespace Factor inline int mul(const int u, const int v) { return 1ll * u * v % MOD; }
inline void addeq(int& u, const int v) { (u += v) >= MOD && (u -= MOD); }
inline int mpow(int u, int v) {
int ret = 1;
for (; v; u = mul(u, u), v >>= 1) ret = mul(ret, v & 1 ? u : 1);
return ret;
} namespace Power2 { const int SM = 31596;
int sma[SM + 1], gnt[SM + 1]; inline void init() {
sma[0] = 1;
rep (i, 1, SM) addeq(sma[i] = sma[i - 1], sma[i - 1]);
gnt[0] = 1, gnt[1] = sma[SM];
rep (i, 2, SM) gnt[i] = mul(gnt[i - 1], gnt[1]);
} inline int power(const int u) {
return mul(sma[u % SM], gnt[u / SM]);
} } // namespace Power2 inline int calc(const __gnu_pbds::gp_hash_table<LL, int>
::iterator&& it, LL d, LL phi) {
if (it == fct.end()) {
return mul(phi % MOD, Power2::power(2 * d % (MOD - 1)
* (m % (MOD - 1)) % (MOD - 1)));
} int ret = 0;
rep (i, 0, it->se) {
if (i == repi || it->fi != 2) addeq(ret, calc(std::next(it), d, phi));
if (i == repi) break;
d *= it->fi, phi /= it->fi - (i + 1 == repi);
}
return ret;
} int main() {
freopen("ntt.in", "r", stdin);
freopen("ntt.out", "w", stdout); Power2::init();
int T; scanf("%d", &T);
while (T--) {
scanf("%lld %lld", &n, &m);
fct.clear(), Factor::factor(n, fct);
LL phi = n;
for (const auto& p: fct) phi = phi / p.fi * (p.fi - 1);
printf("%d\n", mul(mpow(n % MOD, MOD - 2), calc(fct.begin(), 1, phi)));
}
return 0;
}

Solution -「NOI Simu.」逆天题的更多相关文章

  1. Solution -「基环树」做题记录

    写的大多只是思路,比较简单的细节和证明过程就不放了,有需者自取. 基环树简介 简单说一说基环树吧.由名字扩展可得这是一类以环为基础的树(当然显然它不是树. 通常的表现形式是一棵树再加一条非树边,把图画 ...

  2. Solution -「NOI 2021」「洛谷 P7740」机器人游戏

    \(\mathcal{Description}\)   Link.   自己去读题面叭~ \(\mathcal{Solution}\)   首先,参悟[样例解释 #2].一种暴力的思路即为钦定集合 \ ...

  3. Solution -「NOI 2020」「洛谷 P6776」超现实树

    \(\mathcal{Description}\)   Link.   对于非空二叉树 \(T\),定义 \(\operatorname{grow}(T)\) 为所有能通过若干次"替换 \( ...

  4. Solution -「NOI 2016」「洛谷 P1587」循环之美

    \(\mathcal{Description}\)   Link.   给定 \(n,m,k\),求 \(x\in [1,n]\cap\mathbb N,y\in [1,m]\cap \mathbb ...

  5. Solution -「NOI 2012」「洛谷 P2050」美食节

    \(\mathcal{Description}\)   Link.   美食节提供 \(n\) 种菜品,第 \(i\) 种的需求量是 \(p_i\),菜品由 \(m\) 个厨师负责制作,第 \(j\) ...

  6. Solution -「NOI 2008」「洛谷 P3980」志愿者招募

    \(\mathcal{Description}\)   Link.   一项持续 \(n\) 天的任务,第 \(i\) 天需要至少 \(a_i\) 人工作.还有 \(m\) 种雇佣方式,第 \(i\) ...

  7. Solution -「NOI 2018」「洛谷 P4768」归程

    \(\mathcal{Description}\)   Link.   给定一个 \(n\) 个点 \(m\) 条边的无向连通图,边形如 \((u,v,l,a)\).每次询问给出 \(u,p\),回答 ...

  8. Solution -「ARC 104E」Random LIS

    \(\mathcal{Description}\)   Link.   给定整数序列 \(\{a_n\}\),对于整数序列 \(\{b_n\}\),\(b_i\) 在 \([1,a_i]\) 中等概率 ...

  9. Solution -「NOI 模拟赛」出题人

    \(\mathcal{Description}\)   给定 \(\{a_n\}\),求一个 \(\{b_{n-1}\}\),使得 \(\forall x\in\{a_n\},\exists i,j\ ...

  10. Solution -「NOI.AC 省选膜你赛」union

    题目 题意简述   给定两颗树 \(A,B\),\(A\) 中的任一结点 \(u\) 与 \(B\) 中的任一结点 \(v\) 都有一个关系值 \(f(u,v)\),初始为 \(0\).再给出 \(q ...

随机推荐

  1. Flink CDC 与Hudi整合

    介绍 之前写过Flink CDC sink 到 Iceberg中,本篇主要实践如何CDC到hudi中. 什么是hudi? Hudi is a rich platform to build stream ...

  2. 2.15 Linux中一切皆文件[包含优缺点]

    Linux 中所有内容都是以文件的形式保存和管理的,即一切皆文件,普通文件是文件,目录(Windows 下称为文件夹)是文件,硬件设备(键盘.监视器.硬盘.打印机)是文件,就连套接字(socket). ...

  3. apache2和nginx卸载总是不干净不完全导致无法重装,重装成功也无法启动

    大着胆子把nginx卸载了用的命令是  sudo apt remove nginx 结果最后不知道怎么折腾的就算重新装也装不上了,然后就转头折腾apache2,也卸载了  sudo apt remov ...

  4. 70 个群都来问我的 AI 日报,是这么做的。

    最近我给 FastGPT 用户交流群里接入了 AI 日报,每天早上 10 点会自动向群里推送 AI 日报,让群里的小伙伴们第一时间了解到昨天 AI 领域都发生了哪些大事. 效果大概是这个样子的: 如果 ...

  5. Custom PMD Rules

    by Tom Copeland04/09/2003 A Review of PMD A few weeks ago, O'Reilly Network ran an article on PMD, a ...

  6. 基本ROP

    ret2text [NewStarCTF 2023 公开赛道]ret2text (64) execve本身并不是一个后门函数. 实际上,execve是一个标准的系统调用函数,用于在 Linux和类 U ...

  7. MySQL 8.0 为什么会放弃查询缓存?

    什么是查询缓存? 查询缓存就是将一次查询结果存储在内存中,假如下一次查询结果在内存中,就直接在内存中读取. 设计初衷 当然是提高性能,通过缓存来减少解析器.优化器.存储引擎的执行时间. MySQL查询 ...

  8. 利用 Databend + COS助力 CDH 分析 | 某医药集团

    作者: 黄志武 某医药集团信息中心数据库组组长,13 年数据库行业从业经历,Oracle OCM,关注 Oracle.MySQL.Redis.MongoDB.Oceanbase.Tidb.Polard ...

  9. 百度地图各种控件:地图平移缩放控件NavigationControl、地图类型控件MapTypeControl

    注:代码复制即可用,标色代码为主要代码 百度地图提供了如下控件: 1.Control:控件的抽象基类,所有控件均继承此类的方法.属性.通过此类您可实现自定义控件. 2.NavigationContro ...

  10. Flutter GestureDector点击空白区域不响应

    GestureDector点击空白区域不响应 当GestureDector嵌套Container时,当Container子组件为Text时,点击空白区域不响应点击事件 GestureDetector( ...