uva11426 欧拉函数应用

题目链接:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=121873#problem/F

题目大意:给你一个数n,让你输出(i=1->n-1)(j=i+1->n)gcd(i,j)

思路分析:直接暴力做铁定超时,而且数据也不止一组,因此我们要考虑打表来做这一道题, 既然要打表,就要

寻找递推关系,手写一下,比较容易就可以找到递推关系,S[n]=S[n-1]+f[n]

f[n]=gcd(1,n)+gcd(2,n)+.......+gcd(n-1,n),现在问题就转化成了如何求f[n],直接求目测超时,这一步就

比较奇妙,我们可以从约数开始入手,看约数为1.2.....分别有多少个数,数的个数刚好为phi[j/i]

代码:

#include <iostream>
#include <cmath>
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long ll;
const int maxn=4000000+100;
ll phi[maxn];
ll prime[maxn/10];
ll s[maxn];
ll f[maxn];
bool check[maxn];
int tot;
void make_phi()
{
    phi[1]=1;
    memset(check,true,sizeof(check));
    tot=0;
    for(ll i=2;i<maxn;i++)
    {
        if(check[i])
        {
            prime[tot++]=i;
            phi[i]=i-1;
        }
        for(int j=0;j<tot&&i*prime[j]<=maxn;j++)
        {
            check[i*prime[j]]=false;
            if(i%prime[j]==0)
            {
                phi[i*prime[j]]=phi[i]*prime[j];
            }
            else phi[i*prime[j]]=phi[i]*(prime[j]-1);
        }
    }
}
void init()
{
    memset(f,0,sizeof(f));
    for(int i=1;i<maxn;i++)//打表求f[i]
    {
        for(int j=2*i;j<=maxn;j+=i)
        {
            f[j]+=i*phi[j/i];
        }
    }
    s[1]=0;
    for(ll i=2;i<maxn;i++)
    {
        s[i]=s[i-1]+f[i];
    }
}
int main()
{
    ll n;
    make_phi();
    init();
    while(scanf("%lld",&n)&&n)
    {
         printf("%lld\n",s[n]);
    }
}

 

posted on 2016-07-16 16:57  当蜗牛有了理想  阅读(162)  评论(0编辑  收藏  举报

导航