BZOJ2705: [SDOI2012]Longge的问题

【传送门:BZOJ2705


简要题意:

  给出一个n,输出Σgcd(i,n)(1<=i<=n)


题解:

  首先数据范围惊人,然后要加long long!!

  怎么做呢?

  就是先求出n的所有因数

  设a[i]表示n的第i个因子,f[i]为以第i个因子为最大公约数的个数

  然后一般情况下f[i]应该是n/i

  但是我们先来看数据:

  6的因子为:1,2,3,6

  那么f[6]=1是无可非议的

  但是f[3]并不等于2,而是等于1,为什么?

  因为f[6]中已经计算了6,而f[3]中也把6也算了进去,显然是不对的

  那么我们就从后往前求f数组,然后先将f[i]=n/a[i],然后往后面找是否有a[j]%a[i]==0(1<=i<j<=n),如果有,则f[i]-=f[j]

  就好像容斥一样做就可以了

  注意得出来的∑f[i]并不是最终答案,∑f[i]*a[i]才是要的答案


参考代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
using namespace std;
typedef long long LL;
LL a[11000];
LL f[11000];
int main()
{
    LL n;
    scanf("%lld",&n);
    LL t=int(double(sqrt(n+1)));
    int len=0;
    memset(f,0,sizeof(f));
    for(LL i=1;i<=t;i++)
    {
        if(n%i==0)
        {
            a[++len]=i;
            if(i*i!=n) a[++len]=n/i;
        }
    }
    f[len]=1;
    sort(a+1,a+len+1);LL ans=a[len];
    for(int i=len-1;i>=1;i--)
    {
        f[i]=n/a[i];
        for(int j=len;j>i;j--)
        {
            if(a[j]%a[i]==0)
            {
                f[i]-=f[j];
            }
        }
        ans+=f[i]*a[i];
    }
    printf("%lld\n",ans);
    return 0;
}

 

posted @ 2017-12-21 21:16  Star_Feel  阅读(211)  评论(0编辑  收藏  举报