HDU 5212 code (莫比乌斯反演)

来源:互联网 发布:好人 知乎 编辑:程序博客网 时间:2024/05/21 08:03

思路:

首先看数据范围1e4就知道不能用n^2的方法。
所以我们要统计每个数作为gcd对答案的贡献。
而统计一个区间内有多少个 gcd(i,j)=k 的无序数对,当然就是上莫比乌斯喽~
反演式:
这里写图片描述

对于这道题,由于是给定的n个数,而不是一个区间,所以我们不能o(1)的求出F(i)的值了,所以先nlogn的预处理出F(i)的的值,然后nlogn的统计出所有f(i)。
然后对于每个f(i),我们把它的贡献加到答案中:f(i)i(i1) (注意取mod)

#include<stdio.h>#include <iostream>#include<string.h>#include<math.h>#include<algorithm>#define eps 1e-8typedef long long int lli;using namespace std;const int maxn = 1e4+10;const int mod = 10007;bool isprime[maxn];//int phi[maxn];int prime[maxn],miu[maxn];void moblus(){    int cnt = 0;miu[1] = 1;    for(lli i = 2;i < maxn;i++){        if(!isprime[i]){            prime[cnt++] = i,miu[i] = -1;//phi[i] = i-1;        }        for(lli j = 0;j < cnt && i*prime[j] < maxn;j++){            lli x = prime[j];            isprime[i*x] = 1;            if(i%x){                miu[i*x] = -miu[i];                //phi[i*x] = phi[i] * phi[x];            }            else{                miu[i*x] = 0;                //phi[i*x] = phi[i] * x;                break;            }        }    }}int a[maxn];int f[maxn];int gc[maxn];int main(){    moblus();    int n,v;    while(~scanf("%d",&n)){        memset(a,0,sizeof(a));        memset(f,0,sizeof(f));        memset(gc,0,sizeof(gc));        int maxa = -0x3f3f3f3f;        for(int i = 1;i <= n;i++){            scanf("%d",&v);            a[v]++;            maxa = max(maxa,v);        }        for(int i = 1;i <= maxa;i++){            for(int j = 1;j*i<=maxa;j++){                f[i] += a[i*j];            }        }        for(int i = 2;i <= maxa;i++){            for(int j = 1;j*i<=maxa;j++){                gc[i] += miu[j]*f[j*i]*f[j*i];            }        }        int ans = 0;        for(int i = 2;i <= maxa;i++){            ans += gc[i]%mod *i%mod*(i-1)%mod;            ans %= mod;        }        printf("%d\n",ans%mod);    }    return 0;}