spoj5971 LCM Sum

####题目链接:猛戳这里
####题目大意:
∑ i = 1 n l c m ( i , n ) \sum_{i=1}^{n}lcm(i,n) i=1nlcm(i,n),比51nod上那道最小公倍数之和V2要简单。
####解题思路:
因为是上面那道题的简单版,所以可以直接套用上题的思路。又因为这道起点比较特殊又可以稍加变化速度也更快。
∑ i = 1 n l c m ( i , n ) = ∑ i = 1 n i ∗ n g c d ( i , n ) = n × ∑ i = 1 n i g c d ( i , n ) \sum_{i=1}^{n}lcm(i,n)=\sum_{i=1}^{n}\frac{i*n}{gcd(i,n)}=n\times\sum_{i=1}^{n}\frac{i}{gcd(i,n)} i=1nlcm(i,n)=i=1ngcd(i,n)in=n×i=1ngcd(i,n)i
到此两种方法的处理都相同。以后枚举每个因子,对每个因子所对应的和求的方法不同。

  1. n × ∑ d ∣ n n v × ( n v + 1 ) ÷ 2 × ∑ d ′ ∣ d μ ( d ′ ) × d ′ n\times\sum_{d\mid n}\frac{n}{v}\times(\frac{n}{v}+1)\div2\times\sum_{d'\mid d}\mu(d')\times d' n×dnvn×(vn+1)÷2×ddμ(d)×d f ( d ) = ∑ d ′ ∣ d μ ( d ′ ) × d ′ f(d)=\sum_{d'\mid d}\mu(d')\times d' f(d)=ddμ(d)×d, f ( d ) f(d) f(d)是积性函数, f ( p ) = 1 − p f(p)=1-p f(p)=1p。具体过程参见上面链接
  2. n × ( 1 + ∑ d ∣ n d × φ ( d ) / 2 ) n\times(1+\sum_{d\mid n}d\times\varphi(d)/2) n×(1+dnd×φ(d)/2)
    ####代码:
    莫比乌斯反演,复杂度 O ( T n ∗ 256 ∗ 8 ) O(T\sqrt n*256*8) O(Tn 2568)
/* ********************************
Author			: danmu
Created Time	: 2016年07月12日 星期二 20时43分40秒
File Name		: spoj5971.pp
******************************** */

#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <string>
#include <vector>
#include <cstdio>
#include <stack>
#include <queue>
#include <cmath>
#include <list>
#include <map>
#include <set>

#define rep(i,x,y) for(int i=x;i<=y;++i)
#define _rep(i,x,y) for(int i=x;i>=y;--i)
#define CL(S,x) memset(S,x,sizeof(S))
#define CP (S1,S2) memcpy(S1,S2,sizeof(S2))
#define ALL(x,S) for(x=S.begin();x!=S.end();++x)
#define ULL unsigned long long
#define PI 3.1415926535
#define INF 0x3f3f3f3f
#define LL long long

const int maxn = 1005;

using namespace std;
int n;
int prime[maxn];
bool check[maxn];
int pri[50],pri_cnt;
int len[50];
vector<int> fac;
LL ans;
void mobius(){
    memset(check,false,sizeof(check));
    prime[0] = 0;
    for(int i=2;i<maxn;++i){
        if(!check[i]){
            prime[++prime[0]] = i;
        }
        for(int j=1;j<=prime[0];++j){
            if(i*prime[j] >= maxn)  break;
            check[i*prime[j]] = true;
            if(i%prime[j] == 0) break;
        }
    }
}
void dfs(int res,int l){
	if(l>=pri_cnt){
		fac.push_back(res);
		return;	
	}	
	dfs(res,l+1);
	int tmp=1;
	for(int i=1;i<=len[l];++i){
		tmp*=pri[l];
		dfs(res*tmp,l+1);	
	}
}
void getFac(){
	pri_cnt=0;
    int b_c=n;
    for(int i=1;i<=prime[0]&&(LL)prime[i]*prime[i]<=b_c;++i){
   		if(b_c%prime[i]==0){
			pri[pri_cnt]=prime[i];
			len[pri_cnt]=0;		             
			while(b_c%prime[i]==0){
				b_c/=prime[i];
				++len[pri_cnt];	
			}
			++pri_cnt;         
     	}
	}
	if(b_c>1){
		pri[pri_cnt]=b_c;
		len[pri_cnt++]=1;	
	}     
	fac.clear();
	dfs(1,0);
}
void work(){
	getFac();
	ans=0;
	for(int i=0;i<fac.size();++i){
		int v=fac[i];
		LL tmp=(LL)n/v*(n/v+1)/2;
		LL res=1;
		for(int j=0;j<pri_cnt;++j){
			if(v % pri[j])  continue;
            LL t = 1-pri[j];
            res = res*t;	
		}
		ans+=res*tmp;
	}
	ans*=n;
}
int main(){
	//freopen("in.txt", "r", stdin);
	//freopen("out.txt", "w", stdout);
	int t;
	mobius();
	scanf("%d",&t);
	while(t--){
		scanf("%d",&n);
		work();
		printf("%I64d\n",ans);
	}	
	system("pause");
	return 0;
}

复杂度 O ( T n ∗ 256 ) O(T\sqrt n*256) O(Tn 256)

#include<cstdio>
#include<cstdlib>
#include<cstring>
#define LL long long
const int maxn=1000005;
int n;
LL ans=0;
bool ip[1010];
int prime[1010],cnt;
int phi[maxn];
int pri[10],len[10],pri_cnt;
void init(){
	memset(ip,true,sizeof(ip));
	ip[0]=ip[1]=false;
	cnt=0;
	for(int i=2;i<1010;++i){
		if(ip[i]){
			prime[cnt++]=i;
			for(int j=i*i;j<1010;j+=i)
				ip[j]=false;
		}	
	}	
	for(int i=1;i<maxn;++i) phi[i]=i;
	for(int i=2;i<maxn;i+=2) phi[i]/=2;
	for(int i=3;i<maxn;i+=2)
		if(phi[i]==i)
			for(int j=i;j<maxn;j+=i)
				phi[j]=phi[j]/i*(i-1);
}
void getFac(){
	int b_c=n;
	pri_cnt=0;
	for(int i=0;i<cnt&&(LL)prime[i]*prime[i]<=b_c;++i){
		if(b_c%prime[i]==0){
			pri[pri_cnt]=prime[i];
			len[pri_cnt]=0;		             
			while(b_c%prime[i]==0){
				b_c/=prime[i];
				++len[pri_cnt];	
			}
			++pri_cnt;         
     	}	
	}
	if(b_c>1){
		pri[pri_cnt]=b_c;
		len[pri_cnt++]=1;	
	}
}
void dfs(int res,int l){
	if(l>=pri_cnt){
		ans+=(LL)res*phi[res]/2;
		return ;
	}
	int tmp=1;
	for(int i=0;i<=len[l];++i){
		dfs(res*tmp,l+1);
		tmp*=pri[l];
	}	
}
int main(){
	int t;
	init();
	scanf("%d",&t);
	while(t--){
		ans=0;
		scanf("%d",&n);
		getFac();
		dfs(1,0);;		
		printf("%I64d\n",(ans+1)*n);
	}
	system("pause");
	return 0;	
}

####总结:

  1. ∑ i = 1 n i g c d ( i , n ) = 1 + ∑ d ∣ n d × φ ( d ) / 2 = ∑ d ∣ n n v × ( n v + 1 ) ÷ 2 × ∑ d ′ ∣ d μ ( d ′ ) × d ′ \sum_{i=1}^{n}\frac{i}{gcd(i,n)}=1+\sum_{d\mid n}d\times\varphi(d)/2=\sum_{d\mid n}\frac{n}{v}\times(\frac{n}{v}+1)\div2\times\sum_{d&#x27;\mid d}\mu(d&#x27;)\times d&#x27; i=1ngcd(i,n)i=1+dnd×φ(d)/2=dnvn×(vn+1)÷2×ddμ(d)×d
  2. ∑ i = 1 n n g c d ( i , n ) = ∑ d ∣ n d × φ ( d ) = g ( n ) \sum_{i=1}^{n}\frac{n}{gcd(i,n)}=\sum_{d\mid n}d\times\varphi(d)=g(n) i=1ngcd(i,n)n=dnd×φ(d)=g(n)
    这里写图片描述
  3. 一百万以内的数最多有八个质因子,十亿以内的数最多有十二个。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值