[BZOJ2301][HAOI2011]Problem B

题目大意

对于给出的 n 次询问,每次给定 a,b,c,d,k 五个数,询问 x=aby=cd[(x,y)=k] 的值。数据保证 n50000,1ab50000,1cd50000

解析

首先利用容斥原理将一个询问拆分成四个,每次求 x=1ny=1m[(x,y)=k] 的值。考虑莫比乌斯反演,设 F(k)k|(x,y) 的对数,f(k)(x,y)=k 的个数,则有以下关系:

F(k)=x=1nkf(kx)

只需快速求出 F(k)。若 k|x,k|y,则 x=kt1,y=kt2,只需统计有多少对 (t1,t2)。得:

F(k)=nkmk

由莫比乌斯反演可求得 f(k)

f(k)=x=1nk(μ(x)F(kx))=x=1nk(μ(x)nkxmkx)

暴力求 f(k)O(n),注意到 nd 有至多 O(n) 个取值,所以可以考虑使用数论分块求解

证明:

  • 1d<n 时,由于 d 只有 n 个,所以 nd 也至多有 n 个取值。
  • ndn 时,由于 nd 只有 n 个,所以 nd 也只有至多 n 个取值。
  • nd 至多有 O(n) 个取值。

同理 md 也只有至多 O(m) 个取值,所以 nkxmkx 都不变的段数有 O(n+m) 段。对于相等的段,求出 μ 函数的前缀和,即可批量计算这一个段的答案。

Copy
#include <bits/stdc++.h> using namespace std; const int maxn = 50010; int T, tot, prime[maxn], mu[maxn], sum[maxn]; void sieve() { fill(prime, prime + maxn, 1); mu[1] = 1, tot = 0; for (int i = 2; i < maxn; i++) { if (prime[i]) { prime[++tot] = i, mu[i] = -1; } for (int j = 1; j <= tot && i * prime[j] < maxn; j++) { prime[i * prime[j]] = 0; if (i % prime[j] == 0) { mu[i * prime[j]] = 0; break; } else { mu[i * prime[j]] = -mu[i]; } } } for (int i = 1; i < maxn; i++) { sum[i] = sum[i - 1] + mu[i]; } } int calc(int n, int m, int k) { if (n > m) swap(n, m); int ans = 0; n /= k, m /= k; for (int i = 1, nxt = 1; i <= n; i = nxt + 1) { nxt = min(n / (n / i), m / (m / i)); ans += (sum[nxt] - sum[i - 1]) * (n / i) * (m / i); } return ans; } int main() { sieve(); scanf("%d", &T); while (T--) { int a, b, c, d, k; scanf("%d %d %d %d %d", &a, &b, &c, &d, &k); printf("%d\n", calc(b, d, k) - calc(b, c - 1, k) - calc(a - 1, d, k) + calc(a - 1, c - 1, k)); } return 0; }
posted @   AlessandroChen  阅读(150)  评论(0编辑  收藏  举报
编辑推荐:
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示