spoj 5971 LCM SUM 求∑lcm(i,n)

spoj 5971. LCM Sum
Problem code: LCMSUM


Given n, calculate the sum LCM(1,n) + LCM(2,n) + .. + LCM(n,n), where LCM(i,n) denotes the Least Common Multiple of the integers i and n.

 

Input

 

The first line contains T the number of test cases. Each of the next T lines contain an integer n.


Output


Output T lines, one for each test case, containing the required sum.

Example

Sample Input :
3
1
2
5

Sample Output :
1
4
55


Constraints

1 <= T <= 300000
1 <= n <= 1000000

 

/*
spoj 5971 LCM SUM
http://www.spoj.pl/problems/LCMSUM/

 sigma lcm( i, n )  =  sigma ( i * n / gcd( i, n ) )  = n * sigma ( i / gcd( i, n ) )
设 gcd( i, n ) = k,  i = k * j, n = k * m ( j <= m ) ,所以
只要枚举n的每个因数,对于每个因数q,求出小于等于q,且与q互素的数的和,将所有的和加起来就是答案了

(1)对于小于等于q,且与q互素的数的和,有公式 q * phi( p ) / 2,具体证明如下:
    小于N且与N互质的正整数之和, 设为S.
    不妨设这些数为a[1], a[2], ..., a[ phi(N) ], 其中phi(N)是N的欧拉函数值.
    对1 <= i <= phi(N), 由gcd( N, a[i] ) = 1可知gcd( N, N - a[i] ) = 1.
    这里可以采用反证: 设gcd( N, N - a[i] ) = k >  1,
    则 k | N,  k | ( N - a[i] )  ->  k | a[i]  ->  k | gcd( N, a[i] ), 而gcd( N , a[i] ) = 1, 矛盾.
    这样, N - a[1], N - a[2], ..., N - a[ phi(N) ]也对应着原数列, 则有:
    S = a[1] + a[2] + ... + a[ phi(N) ]
    S = (N - a[1]) + (N - a[2]) + ... + (N - a[ phi[N] ])
    两式相加得: S = N * phi(N) / 2.
(2)这题n比较小,可以先预处理1到n的所欧拉函数。
(3)1是特殊情况,我的程序会少算一个1,所以最后加回去了。


*/
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;


const int maxn=1010;
int prime[maxn],vis[maxn],pl;
void _prime( )//求素数
{
   for(int i=2;i<maxn;i++)
   {
       if(vis[i]==0) prime[pl++]=i;
       for(int j=0;j<pl&&i*prime[j]<maxn;j++)
       {
           vis[i*prime[j]]=1;
           if(i%prime[j]==0) break;
       }
   }       
}


int phi[1000100];
void phi_table(int n)//筛选法求欧拉函数
{
 for(int i=2 ; i<= n; i++) phi[i] = 0;
 phi[1]= 1;
 for(int i =2; i<=n ;i ++)
  if(!phi[i])
  for(int j = i ; j<=n; j+=i)
  {
   if(!phi[j]) phi[j] = j;
   phi[j] = phi[j] /i*(i-1);
  }
}
 
int fac[1000],num[1000],fl;//分解因数,fl表示因数个数
long long ans;
void dfs(int id,long long cnt)//枚举n的所有因子 (cnt)
{
    if(id==fl)
    {
        ans+=cnt*phi[cnt]/2;
        return ;
    }
    long long temp=1;
    for(int i=0;i<=num[id];i++)
    {
        dfs(id+1,cnt*temp);
        temp*=fac[id];
    }
}

int main()
{
    phi_table(1000100);//求欧拉函数值
    _prime();//筛选法求素数
    int ci;scanf("%d",&ci);
    while(ci--)
    {
        int n;scanf("%d",&n);
        int b=n;//分解质因数
        fl=0;memset(num,0,sizeof(num));
        for(int i=0;i<pl&&prime[i]*prime[i]<=b;i++)//因为数据不会超,所以直接乘
        {
            if(b%prime[i]==0)
            {
                for(fac[fl]=prime[i];b%prime[i]==0;num[fl]++,b/=prime[i]);
                fl++;
            }
        }  
        if(b>1) num[fl]=1,fac[fl++]=b;
        ans=0;
        dfs(0,1);
        printf("%lld/n",(ans+1)*n);//少算了一个1,最后要加上
    }       
    return 0;
}   
   

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值