[ACM]【think in reverse】AtCoder162 Sum of gcd of Tuples (Hard)

Sum of gcd of Tuples (Hard)

题意:N个元素的元组,元素大小范围为1~K,求所有不同元组的最大公因数之和。
在这里插入图片描述

思路:

GCD学得跟翔一样的我吓哭了 反正就是不会,数也大,显然不能暴力做啊,没经验的本菜鸡就等着比完赛看题解了。
然后看到讨论区的一位大佬,名叫ritik_patel05,给出了吓死我的超神思路。
那我这里就直接开始翻译 就是逆向思维。题目的要求的是总和,那么只需求gcd==1至K的元组的数目,乘上对应的gcd,再进行求和。而我们知道,每个N元组的每个位置都是在1~K中选出一个数字。那么,gcd(1)的个数( n( gcd(1) ) )就是N元组的每个位置都是1的倍数的个数,减掉gcd(2)的个数、gcd(3)的个数,一直到gcd(k)的个数。
即,n( gcd( 1 ) ) = 元组中每个位置都是1的倍数的元组个数 - n( gcd( 2 ) ) - n( gcd( 3 ) ) - n( gcd( 4 ) ) - … - n( gcd( k ) )
而,元组中每个位置都是1的倍数的元组的个数为:1~K中1的倍数的个数^N。而1至K中1的倍数的个数就是K/1。
那么,n( gcd( 1 ) ) = k^n - sum( n( gcd( 1×m ) ) ) (1×m<=k)
推广:n( gcd( p ) ) = (k/p)^n - sum( n( gcd( p×m ) ) ) (p×m<=k)
至此,思路结束。
我真是太菜了啊。

代码:

#include<bits/stdc++.h>
using namespace std;
const int mod=1e9+7;
const int maxn=100003;
typedef long long ll;
ll g[maxn];
ll fastpow(ll a,ll n){
	a%=mod;
	ll ans=1;
	while(n){
		if(n&1) ans=(ans*a)%mod;
		a=(a*a)%mod;
		n>>=1;
	}
	return ans;
}
int main(){
	int n,k;
	scanf("%d%d",&n,&k);
	//gcd=m的个数*m
	//个数: 
	//n(gcd(1)):k^n-sum(n(gcd(1*m)))(1*m<=k)
	//n(gcd(2)):(k/2)^n-sum(n(gcd(2*m)))(2*m<=k) 
	//n(gcd(p)):(k/p)^n-sum(n(gcd(p*m)))(p*m<=k)
	//n(gcd(k)):1
	ll ans=0;
	ll tmp,sum;
	for(int i=k;i>=1;i--){
		tmp=k/i;
		g[i]=fastpow(tmp,n);
		sum=0;
		for(int j=2*i;j<=k;j+=i){
			sum=(sum+g[j])%mod; 
		}
		g[i]=(g[i]-sum+mod)%mod;//这里要再加上mod,防止为负数 
		ans=(ans+(g[i]*i)%mod)%mod;
	} 
	printf("%lld\n",ans);
}
发布了9 篇原创文章 · 获赞 0 · 访问量 99

猜你喜欢

转载自blog.csdn.net/weixin_45497996/article/details/105547624