51nod1188 最大公约数之和 V2

考虑每一个数对于答案的贡献。复杂度是O(nlogn)的。因为1/1+1/2+1/3+1/4......是logn级别的

//gcd(i,j)=2=>gcd(i/2,j/2)=1=>phi(n/d)*d;O(nlogn);
#include<cstdio>
#include<cstring>
#include<cctype>
#include<algorithm>
using namespace std;
#define rep(i,s,t) for(int i=s;i<=t;i++)
#define dwn(i,s,t) for(int i=s;i>=t;i--)
#define clr(x,c) memset(x,c,sizeof(x))
#define ll long long
int read(){
	int x=0;char c=getchar();
	while(!isdigit(c)) c=getchar();
	while(isdigit(c)) x=x*10+c-'0',c=getchar();
	return x;
}
const int nmax=5e6+5;
int pe[nmax>>3],phi[nmax],q[nmax];bool vis[nmax];ll ans[nmax];
void init(int t){
	phi[1]=1;int cnt=0,x;
    rep(i,2,t){
        if(!vis[i]) pe[++cnt]=i,phi[i]=i-1;
        rep(j,1,cnt){
            x=pe[j];if(i*x>t) break;vis[i*x]=1;
            if(i%x==0) {
                phi[i*x]=phi[i]*x;break;
            }else phi[i*x]=phi[i]*phi[x];
        }
    }
    rep(i,1,t) rep(j,2,t/i) ans[i*j]+=i*phi[j];//gcd(n,n)!
    rep(i,1,t) ans[i]+=ans[i-1];
}
int main(){
	int n=read(),mx=0;
	rep(i,1,n) q[i]=read(),mx=max(mx,q[i]);
	init(mx);
	rep(i,1,n) printf("%lld\n",ans[q[i]]);
	return 0;
}

  

题目来源: UVA
基准时间限制:2 秒 空间限制:262144 KB 分值: 160 难度:6级算法题
 收藏
 关注
给出一个数N,输出小于等于N的所有数,两两之间的最大公约数之和。
 
 
 
相当于计算这段程序(程序中的gcd(i,j)表示i与j的最大公约数):
 
G=0;
for(i=1;i<N;i++)
for(j=i+1;j<=N;j++)
{
    G+=gcd(i,j);
}
 
Input
第1行:1个数T,表示后面用作输入测试的数的数量。(1 <= T <= 50000)
第2 - T + 1行:每行一个数N。(2 <= N <= 5000000)
Output
共T行,输出最大公约数之和。
Input示例
3
10
100
200000
Output示例
67
13015
143295493160
posted @ 2016-09-11 20:57  BBChq  阅读(235)  评论(0编辑  收藏  举报