统计每个数值的出现次数,再把每个除数的频次累加到它的所有倍数。
OJ: luogu
题目 ID: P2926
难度:普及/提高-
标签:约数倍数枚举计数
日期: 2026-07-16 19:20
题意
第
数据范围为
思路
朴素枚举
直接枚举有序牛对
/**
* Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
* rbook: -> https://rbook.roj.ac.cn https://rbook2.roj.ac.cn
* rainboy的学习导航网站: https://idx.roj.ac.cn
* create_at: 2026-07-19 11:59
* update_at: 2026-07-19 11:59
*/
#include <bits/stdc++.h>
using namespace std;
// brute.cpp:小数据朴素解,直接检查每一对牛是否满足整除关系。
const int MAXN = 105;
int n;
int value[MAXN];
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin >> n;
for (int i = 1; i <= n; i++) cin >> value[i];
for (int i = 1; i <= n; i++) {
int answer = 0;
for (int j = 1; j <= n; j++) {
if (i != j && value[i] % value[j] == 0) answer++;
}
cout << answer << '\n';
}
return 0;
}这种写法完全对应题意,适合作为小数据参考答案,但需要
相同数值只计算一次
两头数值同为
对于某个数值 frequency[d] 头牛,所以包含自己的暂时计数为:
可以为每个
因此枚举每个实际出现的 frequency[d] 加到所有倍数的 divisor_count 中即可。
为什么最后只减一
divisor_count[A_i] 统计所有满足
如果还有其它牛与 frequency[A_i] 是多少,都只减 1,不能减去整个频次。
以样例中数值为 2 的牛为例,能整除 2 的牛的数值是 1,2,2,暂时计数为 3。减去当前牛自己后,仍可拍数值为 1 的牛和另一头数值为 2 的牛,答案为 2。
原 main.py 也采用倍数贡献,但最坏分布下要在 Python 解释器中执行上千万次内层累加,因此没有通过评测。C++ 使用大小约为
正确性说明
固定一个数值 frequency[d] 加入 divisor_count[x]。这与条件
因此累加结束后,divisor_count[x] 恰好等于所有数值能整除 1 后,得到它应该拍的其它牛数量。算法不会遗漏或重复统计任何牛。
代码
/**
* Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
* rbook: -> https://rbook.roj.ac.cn https://rbook2.roj.ac.cn
* rainboy的学习导航网站: https://idx.roj.ac.cn
* create_at: 2026-07-19 11:59
* update_at: 2026-07-19 14:31
*/
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 100005;
const int MAXV = 1000005;
int n;
int value[MAXN];
int frequency[MAXV];
int divisor_cow_count[MAXV];
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin >> n;
int maximum = 0;
for (int i = 1; i <= n; i++) {
cin >> value[i];
frequency[value[i]]++;
if (maximum < value[i]) maximum = value[i];
}
// 数值 d 的每头牛,都会被数值为 d,2d,3d,... 的牛拍到。
for (int divisor = 1; divisor <= maximum; divisor++) {
if (frequency[divisor] == 0) continue;
for (int multiple = divisor; multiple <= maximum; multiple += divisor) {
divisor_cow_count[multiple] += frequency[divisor];
}
}
for (int i = 1; i <= n; i++) {
// 统计中包含当前牛自己,题目要求只拍其它牛。
cout << divisor_cow_count[value[i]] - 1 << '\n';
}
return 0;
}复杂度
设最大输入值为
- 统计频率和输出答案需要
时间。 - 倍数枚举次数为
,上界可写为 。 - 总时间复杂度为
,空间复杂度为 。 brute.cpp时间复杂度为,只用于小数据验证。
总结
本题要复用“相同数值拥有相同答案”。先按值统计频率,再从除数出发把贡献推给所有倍数,就能一次求出每个数值的约数牛总数。最后只减去当前牛自己,重复值对应的其它牛仍会被正确保留。