专栏文章
题解:CF547C Mike and Foam
CF547C题解参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @mipdzrkd
- 此快照首次捕获于
- 2025/12/03 10:27 3 个月前
- 此快照最后确认于
- 2025/12/03 10:27 3 个月前
CF547C
题意
给定一个长度为 的序列 ,有 次操作,每次操作给定一个整数 ,如果 已经被取出,就放回 ,否则取出 。
每次操作后输出取出的数字中满足 且 的二元组 的数量。
思路
假设当前需要取出 ,那么只需考虑取出 对答案的贡献。
设之前已被取出的数共 个,分别为 。
那么 的贡献就是
考虑对式子进行变换,有
对于 ,由定义可知,当 或 时,。
所以可以考虑只枚举满足 的因子 。
因此,将 质因数分解,设 。
由于 ,所以 。
之后直接枚举这 个质因子中选择哪几个 组成 即可,共有 种。
对于枚举的每一个 ,还需知道所有的 中有多少为 的倍数。
由于 中的每个质因子的次数都为 ,所以如果 为 的倍数,那么当 被取出时,在枚举 的满足 的因子 时必定会枚举到 ,可以在枚举时直接统计数量。
放回 同理。
代码
CPP#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10, M = 5e5 + 10;
int n, q, a[N], c[M], ct;
long long cnt;
bool f[N];
int main() {
ios::sync_with_stdio(0), cin.tie(0);
cin >> n >> q;
for (int i = 1; i <= n; i++) cin >> a[i];
while (q--) {
int x; cin >> x;
int tmp = a[x];
vector<int> pr;
for (int i = 2; i * i <= tmp; i++) {
bool flag = 0;
while (tmp % i == 0) flag = 1, tmp /= i;
if (flag) pr.push_back(i);
}
if (tmp != 1) pr.push_back(tmp);
if (!f[x]) {
cnt += ct, ct++;
for (int i = 1; i < (1 << pr.size()); i++) {
int val = 1, k = 1;
for (int j = 0; j < pr.size(); j++) {
if (i & (1 << j)) val *= -1, k *= pr[j];
}
cnt += val * c[k], c[k]++;
}
} else {
ct--, cnt -= ct;
for (int i = 1; i < (1 << pr.size()); i++) {
int val = 1, k = 1;
for (int j = 0; j < pr.size(); j++) {
if (i & (1 << j)) val *= -1, k *= pr[j];
}
c[k]--, cnt -= val * c[k];
}
}
cout << cnt << '\n';
f[x] ^= 1;
}
return 0;
}
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...