BZOJ2226 & SPOJ5971:LCMSum——题解

http://www.lydsy.com/JudgeOnline/problem.php?id=2226

题目大意:给定一个n,求lcm(1,n)+lcm(2,n)+……+lcm(n,n)。

——————————————————————————————

如果是刚做完[SDOI2012]Longge的问题的话这道题应该能轻松一些。

显然答案可以转化为n*i/gcd(n,i)。

设k=gcd(n,i),则可以转化为∑n*i/k(k|n且gcd(n,i)=k),然后变成n*(∑i/k)(k|n且gcd(n,i)=k)

又因为gcd(n/k,i/k)=1,所以对于一个k,∑i/k就是与n/k互质的数的和。

而对于一个数n,求与n互质的数的和=n*phi(n)/2。

于是这题我们就做完了。

PS:秉承着万恶的SPOJ题的尿性,这题有点卡常数。

 

#include<cstdio>
#include<queue>
#include<cctype>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=1000010;
ll phi[N],su[N];
bool he[N];
void Euler(int n){
    int tot=0;
    phi[1]=1;    
    for(int i=2;i<=n;i++){    
    if(!he[i]){    
        su[++tot]=i;    
        phi[i]=i-1;
    }    
    for(int j=1;j<=tot;j++){    
        if(i*su[j]>=n)break;    
        he[i*su[j]]=1;   
        if(i%su[j]==0){    
        phi[i*su[j]]=phi[i]*su[j];break;    
        }    
        else phi[i*su[j]]=phi[i]*(su[j]-1);  
    }
    }
    return;
}    
int main(){
    Euler(1000001);
    int t;
    scanf("%d",&t);
    while(t--){
    int n;ll ans=0;
    scanf("%d",&n);
    for(int i=1;i*i<=n;i++){
        if(n%i)continue;
        int k=n/i;
        ans+=(ll)(phi[k]*k+1)>>1;
        if(i*i<n)ans+=(ll)(phi[i]*i+1)>>1;
    }
    printf("%lld\n",ans*n);
    }
    return 0;
}

 

 

posted @ 2018-01-04 15:31  luyouqi233  阅读(183)  评论(0编辑  收藏  举报