标签:getch 快速 printf prime ret long etc 怎么 main
题目让我们求
\[\sum_{i=1}^n\sum_{j=i+1}^{n}gcd(i,j)\]
\[\sum_{i=1}^n\sum_{j=1}^{i-1}gcd(i,j)\]
设\(g(n) = \sum_{i=1}^{n-1}gcd(i,n)\)
\[\sum_{i=1}^ng(i)\]
考虑如何快速求\(g\)
\[g(n)=\sum_{i=1}^{n-1}gcd(i,n)\]
设\(gcd(i,n)==d\)
换个方向枚举
\[g(n)=\sum_{d=1}^{n-1}d\sum_{i=1}^n[gcd(i,n) == d]\]
\[g(n)=\sum_{d=1}^{n-1}d\sum_{i=1}^n[gcd(i,n) == d]\]
\[g(n)=\sum_{d=1}^{n-1}d\sum_{i=1}^{\frac nd}[gcd(i,\frac nd) == 1]\]
\[g(n)=\sum_{d=1}^{n-1}d\phi(\frac nd)\]
然后筛一下g(n),直接前缀和O(1)询查
怎么筛:枚举因子d,然后直接暴力+d,这就是著名的调和级数
rep(i , 1, N){
for(int j = 2 * i;j <= N;j += i)
g[j] += i * phi[j / i];
}
AC代码:
#include <iostream>
#include <cstdio>
#define rep(i , x, p) for(register int i = x;i <= p;++ i)
#define gc getchar()
#define pc putchar
#define ll long long
const int maxN = 1e7 + 7;
int num , prime[maxN], phi[maxN];
bool is_prime[maxN];
ll sum[maxN] , g[maxN];
inline void init() {
int N = 1000000;
phi[1] = 1;
rep(i , 2, N) {
if(!is_prime[i]) prime[++ num] = i , phi[i] = i - 1;
for(register int j = 1;j <= num && i * prime[j] <= N;++ j) {
is_prime[i * prime[j]] = true;
if(i % prime[j] == 0) {
phi[i * prime[j]] = phi[i] * prime[j];
break;
}
phi[i * prime[j]] = phi[i] * ( prime[j] - 1 );
}
}
rep(i , 1, N){
for(int j = 2 * i;j <= N;j += i)
g[j] += i * phi[j / i];
}
rep(i , 1, N) sum[i] = sum[i - 1] + g[i];
}
int main() {
int n;
init();
while(scanf("%d",&n) == 1 && n) {
printf("%lld\n",sum[n]);
}
return 0;
}
标签:getch 快速 printf prime ret long etc 怎么 main
原文地址:https://www.cnblogs.com/gzygzy/p/10122784.html