NC20812 绿魔法师
题目
题目描述
“我不知道你在说什么,因为我只是个pupil。”--绿魔法师
一个空的可重集合S。
n次操作,每次操作给出x,k,p,执行以下操作:
1、在S中加入x。
2、输出 。
输入描述
所有输入的数都是小于1e5+1的正整数。
输出描述
输出对应的结果
示例1
输入
3 4 1 9 5 2 8 6 3 7
输出
4 2 1
题解
知识点:因数集合,GCD与LCM,容斥原理,枚举。
每次插入一个数 时,因为 的值一定不会出现 因数之外的数,所以考虑枚举这个数的因数 作为 时的贡献,即有多少个 满足条件。
我们先预处理出数据范围内所有数的因数,用 表示整个集合中存在因数 的数的个数,方便之后计数。
因为是最大公约数,应该先考虑较大数的贡献,计算完较大数后,在计算较小数时应减去较大数的影响,所以我们从大到小枚举因数,同时对较小因数做一个容斥。
因此,每次加入一个数 时,用 表示 中 的个数,即 产生的贡献。那么, 应该等于 减去它所有是 的因数的倍数 的贡献 ,即 。这个可以在我们遇到 时对它的因数贡献减去 来维护。
最后,对于一个因数 产生的贡献为 ,累和即可。
复杂度的上界确实是 ,但是跑不满,因为因数个数的上界 是非常松的,这里的总计算量级差不多 。
时间复杂度
空间复杂度
代码
#include <bits/stdc++.h> using namespace std; using ll = long long; vector<int> factor[100007]; void get_factor(int n) { for (int i = n;i >= 1;i--) for (int j = 1;i * j <= n;j++) factor[i * j].push_back(i); } int qpow(int a, int k, int P) { int ans = 1; while (k) { if (k & 1) ans = 1LL * ans * a % P; k >>= 1; a = 1LL * a * a % P; } return ans; } int cnt[100007];//S中i的倍数的个数 int tot[100007];//gcd(x,y)=i的y的个数,通过容斥维护 int main() { std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); get_factor(100000); int n; cin >> n; for (int i = 1;i <= n;i++) { int x, k, p; cin >> x >> k >> p; int ans = 0; for (auto d : factor[x]) { tot[d] += ++cnt[d];// 以d为gcd的个数 = d的倍数个数 - d的倍数作为gcd的数字个数 if (!tot[d]) continue; (ans += 1LL * tot[d] * qpow(d, k, p) % p) %= p; int tmp = tot[d]; for (auto dd : factor[d]) tot[dd] -= tmp; // 给dd减去的其倍数d作为gcd的数字个数 } cout << ans << '\n'; } return 0; }
本文来自博客园,作者:空白菌,转载请注明原文链接:https://www.cnblogs.com/BlankYang/p/17658259.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧