hdu6053-莫比乌斯反演

来源:互联网 发布:58网络公关公司 编辑:程序博客网 时间:2024/05/20 02:23
题解:这里用莫比乌斯反演里面一个函数,它的定义如下:

 

    (1)若,那么

    (2)若均为互异素数,那么

    (3)其它情况下

因为取A数组中的最小值,然取比他小所有的素数然后每个素数贡献的答案就是所有的A[i]/p(p是素数)相乘起来

然后总和,当然这其中会有重复的要用到容斥,重复的就是这些的素数的可以组成的公倍数然后可以用莫比乌斯反演来

同时,可以用T保存前缀然后用快速幂求即可


#include<iostream>#include<cstring>#include<algorithm>#include<cstdio>using namespace std;typedef long long int ll;const int mx = 1e5+5;const int INF = 0x3f3f3f3f;const ll mod = 1e9+7;int u[mx],p[mx],vis[mx];void init(){    u[1] = 1;    for(int i = 2; i < mx; i++){        if(!vis[i]) p[++p[0]]=i,u[i] = -1;        for(int j = 1; j <= p[0] && p[j]*i<mx; j++){                vis[i*p[j]] = 1;                if(i%p[j]==0){                    u[i*p[j]] = 0;                    break;                }                else                    u[i*p[j]] = -u[i];        }    }}int T[2*mx];ll quick(ll x,int n){    ll ans = 1;    while(n){        if(n&1) ans = ans*x%mod;        x = x*x%mod;        n/=2;    }    return ans;}int main(){    int t;    init();    int n;    scanf("%d",&t);    for(int casei = 1; casei <= t; casei++){        memset(T,0,sizeof(T));        int MAX = 0,MIN = INF;        scanf("%d",&n);        for(int i = 1; i <= n; i++){            int a;            scanf("%d",&a);            MIN = min(MIN,a);            MAX = max(MAX,a);            T[a]++;        }        for(int i = MAX; i >= 0; i--)            T[i]+=T[i+1];        ll ans = 0;        for(int i = 2; i <= MIN; i++){            ll ret = -u[i];            if(ret==0)                continue;            int cnt = 1,p = i;            while(p<=MAX) ret = (ret*quick(cnt++,T[p]-T[p+i])%mod+mod)%mod,p+=i;            ans = (ans+ret)%mod;        }        printf("Case #%d: %I64d\n",casei,ans);    }    return 0;}


原创粉丝点击