【luogu 1457】在表格里造序列(莫反)(杜教筛)

在表格里造序列

题目链接:luogu 1457

题目大意

有一个 n*n 的表格,每个位置有一些数列,其中 i 行 j 列里面的数列是所有满足长度为 m,值域是 1~n,且所有值的 gcd 与 i,j 的 gcd 相同的数组。
问你表格里总共有多少个数组。

思路





csp


考虑枚举 gcd 的值,再分别枚举由多少个数组以及多少个表格上的位置满足条件。
d=1n(x=1ny=1n[gcd(x,y)=d])(a1=1n...am=1n[gcd(a1,...,am=d)])
d=1n(x=1ndy=1nd[gcd(x,y)=1])(a1=1nd...am=1nd[gcd(a1,...,am=1)])
d=1n(x=1ndy=1ndp|gcd(x,y)μ(p))(a1=1nd...am=1ndp|gcd(a1,...,am)μ(p))
d=1n(p=1ndμ(p)x=1ndpy=1ndp)(p=1ndμ(p)a1=1ndp...am=1ndp)
d=1n(p=1ndμ(p)(ndp)2)(p=1ndμ(p)(ndp)m)

d=1np=1ndμ(p)(ndp)m=nm
p=1nμ(p)(np)m=nmd=2np=1ndμ(p)(ndp)m
p=1nμ(p)(np)m=fn

fn=nmd=2nfnd

d=1n(p=1ndμ(p)(ndp)2)(fnd)

其中 f 可以记忆化一下在常规整除分块做到 O(n34),左边的一坨式子,都可以用杜教筛快速 rush μ 前缀和也是 O(n34) 从而通过题目捏。

代码

#include<cmath> #include<cstdio> #define ll long long #define mo 998244353 using namespace std; const int Lim = 1e6; const int B = 2e5 + 100; ll n, m, lim, mus[Lim + 100]; ll rem_f[B], rem_mu[B], prime[Lim + 100]; bool np[Lim + 100]; int id(ll x) { if (x <= lim) return x; return lim + n / x; } ll ksm(ll x, ll y) { ll re = 1; while (y) { if (y & 1) re = re * x % mo; x = x * x % mo; y >>= 1; } return re; } ll get_f(ll now) { if (rem_f[id(now)] != -1) return rem_f[id(now)]; ll re = ksm(now, m); for (ll L = 2, R; L <= now; L = R + 1) { R = now / (now / L); (re += mo - (R - L + 1) % mo * get_f(now / L) % mo) %= mo; } return rem_f[id(now)] = re; } ll ask(ll now) { if (now <= Lim) return (mus[now] % mo + mo) % mo; if (rem_mu[id(now)] != -1) return rem_mu[id(now)]; ll re = 1; for (int L = 2, R; L <= now; L = R + 1) { R = now / (now / L); (re += mo - (R - L + 1) * ask(now / L) % mo) %= mo; } return rem_mu[id(now)] = re; } ll slove(ll n) { ll ans = 0; for (ll L = 1, R; L <= n; L = R + 1) { R = n / (n / L); ll mus = (ask(R) - ask(L - 1) + mo) % mo; (ans += mus * (n / L) % mo * (n / L) % mo) %= mo; } return ans; } int main() { for (int i = 0; i < B; i++) rem_f[i] = rem_mu[i] = -1; mus[1] = 1; for (int i = 2; i <= Lim; i++) { if (!np[i]) mus[i] = -1, prime[++prime[0]] = i; for (int j = 1; j <= prime[0] && i * prime[j] <= Lim; j++) { np[i * prime[j]] = 1; if (i % prime[j] == 0) break; else mus[i * prime[j]] = -mus[i]; } mus[i] += mus[i - 1]; } scanf("%lld %lld", &n, &m); lim = sqrt(n); ll ans = 0; for (ll L = 1, R; L <= n; L = R + 1) { R = n / (n / L); (ans += (R - L + 1) % mo * slove(n / L) % mo * get_f(n / L) % mo) %= mo; } printf("%lld", ans); return 0; }

__EOF__

本文作者あおいSakura
本文链接https://www.cnblogs.com/Sakura-TJH/p/luogu_1457.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   あおいSakura  阅读(40)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
历史上的今天:
2021-10-31 【luogu P4720】【模板】扩展卢卡斯定理/exLucas(数论)(CRT)
2021-10-31 【LGR-096】洛谷 11 月月赛 I Div.2 题解
点击右上角即可分享
微信分享提示