zoukankan      html  css  js  c++  java
  • poj 2480

    题目链接:http://poj.org/problem?id=2480

    题意:计算Σgcd(i,n) ,1<=i<=n。

    思路:这题与51nod 1040是一样的题目。

    每一项都是n的因子,我们要求的就是每个因子v的个数。
    可以转换成求gcd(i/v,n/v)=1个数 (i/v是0~n/v ) n/v也是n的因数
    答案就是sum(p*phi(n/p))了(p是因子,phi()是欧拉函数,sum是求和)。但是数据比较大,用因子乘欧拉函数会超时。

    这里要用到积性函数的一点知识。因为gcd(i,m*n)是积性函数(gcd(i,n*m)=gcd(i,n)*gcd(i,m),证明百度。。。)

    令f(n)=Σgcd(i,n)=sum(p*phi(n/p))。

    积性函数很容易想到用素因子分解,因为素因子求解是容易的,那么令n=p1k1*p2k2*..*pmkm

    首先就是要求到  f(pr),  因为pr的因子为1,p,p2,p3..pr

    所以  f(pr)= 1*(pr-pr-1) +p*(pr-1-pr-2)+p2*(pr-2-pr-3)+...+pr-1(p-1)  +pr*1

         =(pr-pr-1)+(pr-pr-1)+...+(pr-pr-1)+pr  

          = r*(pr-pr-1)+pr= (r+1)*pr-r*pr-1

    f(n)=f(p1k1)*f(p2k2)*...*f(pmkm)

    这样我们就可以根据素因子分解,对每个素因子求解再相乘即可。

    代码:

    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #include<cstring>
    #define inf 0x3f3f3f3f
    using namespace std;
    typedef long long ll;
    
    int main()
    {
        ll n;
        while(cin>>n)
        {
            ll ans=1;
            for(ll i=2;i*i<=n;i++)//素因子分解,类似于欧拉函数 
            {
                if(n%i==0)
                {
                    ll r=0,x=1;//r记录该素因子的次方,x=p^r 
                    while(n%i==0)
                    {
                        n/=i;
                        x*=i;
                        r++;
                    }
                    ans*=(r+1)*x-r*(x/i);//代入上面所求公式    
                }    
            }
            if(n>1)//类似于欧拉函数处理,多了最后一个大于根号n的素因子,一样代入公式 
                ans*=2*n-1;
            cout<<ans<<endl;
        }
        return 0;
    }
  • 相关阅读:
    ANSI C 与 C99的不同
    字符串中含有空格的注意事项
    巧用printf函数
    求数列的和
    数值统计
    平方和与立方和
    求奇数的乘积
    第几天?
    细节之重
    用%*c滤掉回车,ASCII码排序
  • 原文地址:https://www.cnblogs.com/xiongtao/p/10896898.html
Copyright © 2011-2022 走看看