uva11426GCD - Extreme (II)

来源:互联网 发布:赛平 淘宝 编辑:程序博客网 时间:2024/04/30 12:06

链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=18553

题意:给定多个n,求所有的gcd(i,j)之和{1<=i<j<=n}。

分析:因为每一次的gcd必然是j的因子,我们只要对每个j的因子计算贡献即可,比如当前的因子为x,x|j,那么对答案的贡献为phi(j/x)*x,phi()是欧拉函数。O(nlogn)

代码:

#include<map>#include<set>#include<cmath>#include<queue>#include<bitset>#include<math.h>#include<cstdio>#include<vector>#include<string>#include<cstring>#include<iostream>#include<algorithm>#pragma comment(linker, "/STACK:102400000,102400000")using namespace std;const int N=4000010;const int MAX=151;const int mod=100000000;const int MOD1=100000007;const int MOD2=100000009;const double EPS=0.00000001;typedef long long ll;const ll MOD=1000000009;const ll INF=10000000010;typedef double db;typedef unsigned long long ull;int f[N],a[N],q[N];ll ans[N],sum[N];void deal(int n) {    int i,j,k=0,w;    for (i=1;i<=n;i++) f[i]=i;    memset(q,0,sizeof(q));    for (i=2;i<=n;i++) {        if (!q[i]) { a[++k]=i; }        for (j=1;j<=k;j++) {            if (a[j]*i>n) break ;            q[a[j]*i]=1;            if (i%a[j]==0) break ;        }    }    for (i=1;i<=k;i++)        for (j=a[i];j<=n;j+=a[i]) f[j]=f[j]/a[i]*(a[i]-1);    memset(ans,0,sizeof(ans));    for (i=1;i<=n;i++)        for (j=2*i;j<=n;j+=i) ans[j]+=f[j/i]*i;    sum[0]=0;    for (i=1;i<=n;i++) sum[i]=sum[i-1]+ans[i];}int main(){    int n;    deal(4000000);    while (scanf("%d", &n)&&n) printf("%lld\n", sum[n]);    return 0;}


0 0