题解:公倍数问题 [GESP8级]
2025-12-27 11:21:31
发布于:山东
6阅读
0回复
0点赞
首先发现n,m都很大,所以肯定不能建立在二维数组的角度去解决问题。k<=1e6则提示我们每个k要以log以内的复杂度解决问题
其实网格只是个幌子,发现如果一个点(x,y)可以为k,那么x,y一定都是k的因子,则我们只要求出k的因子个数再平方就是答案
不过由于n,m的限制,我们真正要找的是小于等于n,m的k的因数个数,然后再乘起来
发现枚举每个k去找是很难压住复杂度的,那我们不妨正难则反:用类似筛法的思路,对每个 小于等于n,m的数 的倍数开桶记录因数个数,最后对于每个k乘起来即可
程序是这样的:
for(int i=1;i<=n;i++)
for(int j=i;j<=k;j+=i)
sn[j]++;
时间复杂度为 n*(n/1)+n*(n/2)+n*(n/3)+...+n = n*(n+n/2+n/3+...+1) ≈ nlogn(调和级数)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e6 + 7;
int n, m, k;
ll sn[N], sm[N];
void solve()
{
cin >> n >> m >> k;
for(int i = 1; i <= n; i ++){
for(int j = i; j <= k; j += i){
sn[j] ++;
}
}
for(int i = 1; i <= m; i ++){
for(int j = i; j <= k; j += i){
sm[j] ++;
}
}
ll ans = 0;
for(int i = 1; i <= k; i ++){
ans += 1LL * i * sn[i] * sm[i];
}
cout << ans << '\n';
}
signed main()
{
ios :: sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
solve();
return 0;
}
这里空空如也




有帮助,赞一个