1 条题解

  • 0
    @ 2024-6-6 17:10:21

    【题目大意】给定 nn,m,K。定义 anskans_k为满足 iijj 的最小公倍数是 kk 的约数的数对 (i,j)(i,j) 的个数,求 k=1K(kansk)\sum_{k=1}^K(k*ans_k)

    【考纲知识点】数学,调和级数

    【解题思路】 题目求k=1K(kansk)\sum_{k=1}^K(k*ans_k),因此不能直接通过 iijj去更新 kk。而由数据范围,先猜测预处理anskans_k,正着想很难想,我们可以逆向思考; 假设,有一个数 pp,存在一对 (i,j)(i,j)满足上述条件,即 iijj 的最小公倍数 Li,jL_{i,j} 的约数。那么容易得到 ii,jj,都是 pp 的约数。 那么,反过来,是不是就有 ansk=1......nans_k = 1......n中是kk的约数的个数1......m*1......m中是kk的约数的个数; 因为由唯一分解定理易得,一个数的两个约数的最小公倍数一定还是这个数的约数。因此​满足条件的 (i,j)(i,j) 一定在 pp 的约数当中,不满足条件的 (i,j)(i,j) 一定不在 pp 的约数当中​。排列组合一下,即可得到答案。 现在问题变成了怎么预处理一个数的约数个数。 这个简单,类似质数筛的方法,枚举 ii,将符合的 jj 标记一下即可

    【参考程序】

    #include<bits/stdc++.h>
    using namespace std;
    inline long long read(){
    	long long x=0,f=1;
    	char c=getchar();
    	while(c<'0'||c>'9'){
    		if(c=='-') f=-1;
    		c=getchar();
    	}
    	while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+c-'0',c=getchar();
    	return x*f;
    }
    const int K=1e6+10;
    int sumn[K],summ[K];
    int main(){
    	int n=read(),m=read(),k=read();
    	for(int i=1;i<=n;i++)
    		for(int j=i;j<=K;j+=i) sumn[j]++;
    	for(int i=1;i<=m;i++)
    		for(int j=i;j<=K;j+=i) summ[j]++;
    	long long ans=0;
    	for(int i=1;i<=k;i++)
    		ans=ans+(long long)i*sumn[i]*summ[i];//※结论得到
    	cout<<ans;
        return 0;
    }
    
    • 1

    [GESP202403 八级] 公倍数问题

    信息

    ID
    597
    时间
    1000ms
    内存
    128MiB
    难度
    9
    标签
    递交数
    9
    已通过
    5
    上传者