HDU 5212

来源:互联网 发布:cf手游刷枪软件注册码 编辑:程序博客网 时间:2024/06/02 07:18

来自我的新博客

HDU 5212

Description:

       给定一个数列{aN} ,然后求

Ans=i=1Nj=1Ngcd(ai,aj)(gcd(ai,aj)1) Mod 10007  (1<=ai,N<=10000)

      
      
      

Solution:

      首先我们令 num[t] 表示 t 这个数字在数列 {aN} 中出现的次数。

      那么 Ans=10000i=110000j=1num[i]num[j]gcd(i,j)(gcd(i,j)1)

      我们 f(i)=i(i1) ,并且构造函数 fr(d) 使得 f(i)=d|ifr(d)

      所以 Ans=10000i=110000j=1num[i]num[j]d|i,d|jfr(d)

                      `=10000d=1d|id|jnum[i]num[j]fr(d)=10000d=1fr(d)(d|inum[i])2

      最终

Ans=d=110000fr(d)(i=110000dnum[id])2

      fr(d)怎么求?直接根据前面的定义式莫比乌斯反演就行了。

Code:

#include <cstdio>#include <cstdlib>#include <cstring>#include <cmath>#include <algorithm>#include <iostream>using namespace std;const int Mod=10007;int N;int a[10010]={0};int F[10010]={0};int fr[10010]={0};int main(){    for(int i=1;i<=10000;i++)    {        fr[i]=(fr[i]+i*(i-1)%Mod)%Mod;        for(int j=i+i;j<=10000;j+=i)            fr[j]=(fr[j]+Mod-fr[i])%Mod;    }    for(;scanf("%d",&N)!=EOF;)    {        for(int i=1;i<=N;i++)        {            scanf("%d",&a[i]);            F[a[i]]++;        }        int ans=0;        for(int d=1;d<=10000;d++)        {            int sum=0;            for(int i=10000/d;i>=1;i--)                sum=(sum+F[i*d])%Mod;            ans=(ans+sum*sum%Mod*fr[d])%Mod;        }        printf("%d\n",ans);        memset(F+1,0,sizeof(int)*10000);    }    return 0;}
0 0
原创粉丝点击