[ACM] 【umgekehrt denken】 AtCoder162 Summe der gcd von Tupeln (schwer)

Summe der gcd von Tupeln (schwer)

Titel: Tupel von N Elementen, Elementgrößenbereich ist 1 ~ K, finden Sie die Summe des größten gemeinsamen Faktors aller verschiedenen Tupel.
Fügen Sie hier eine Bildbeschreibung ein

Ideen:

Ich habe gelernt, wie man GCD wie Xiang lernt. Ich habe trotzdem geweint . Nein, es ist zu groß. Natürlich kann ich es nicht gewalttätig tun. Der unerfahrene Hahn wird warten, um das Problem nach Beendigung des Spiels zu lösen.
Dann sah ich im Diskussionsbereich einen großen Mann namens ritik_patel05, der mir einen übergeistigen Gedanken gab, der mir Angst machte .
Dann werde ich anfangen direkt zu übersetzen, hier ist umgekehrtes Denken . Die Frage erfordert eine Summe, daher wird nur die Anzahl der Tupel mit gcd == 1 bis K benötigt, multipliziert mit dem entsprechenden gcd und dann summiert. Und wir wissen, dass jede Position jedes N-Tupels eine Zahl ist, die aus 1 ~ K ausgewählt ist. Dann ist die Anzahl von gcd (1) (n (gcd (1))) die Anzahl jeder Position des N-Tupels ist ein Vielfaches von 1 minus der Anzahl von gcd (2), gcd (3) Die Anzahl entspricht der Anzahl von gcd (k).
Das heißt, n (gcd (1)) = Anzahl der Tupel, wobei jede Position im Tupel ein Vielfaches von 1-n ist (gcd (2)) - n (gcd (3)) - n (gcd (4)) -… -N (gcd (k))
Die Anzahl der Tupel, bei denen jede Position im Tupel ein Vielfaches von 1 ist, ist jedoch: die Anzahl der Vielfachen von 1 in 1 ~ K ^ N. Die Anzahl der Vielfachen von 1 von 1 bis K beträgt K / 1.
Dann ist n (gcd (1)) = k ^ n-Summe (n (gcd (1 × m))) (1 × m <= k)
Verallgemeinerung: n (gcd (p)) = (k / p) ^ n-Summe (n (gcd (p × m))) (p × m <= k)
An diesem Punkt ist die Idee vorbei.
Ich bin so lecker.

Code:

#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 Originalartikel veröffentlicht · 0 · 99 Besuche gewonnen

Ich denke du magst

Origin blog.csdn.net/weixin_45497996/article/details/105547624
Empfohlen
Rangfolge