ZOJ 3868 GCD Expectation(莫比乌斯反演)

来源:互联网 发布:地理所用数据 高分 编辑:程序博客网 时间:2024/06/05 11:16

题意就是求序列的所有gcdk次方和。

f(d)表示d=gcd(x1,x2,...,xm)的组数。

F(d)表示d|gcd(x1,x2,...,xm)的组数。

F(x)=x|df(d)

f(x)=x|dμ(dx)F(d)

F(d)求法:

d|x1,d|x2,d|x3,...,d|xmn个数中d能整除cnt(d)个。F(d)=2cnt(d)1

每一次ai的最大值为mx

o(mx)的复杂度内预处理出F(d)的值。

预处理完了以后o(mxlog(mx))处理出f(x)的值。

要求的答案:ans=ni=1f(i)ik这里omxlogk)的复杂度搞定。

总的复杂度:o(mxlog(mx)+mxlogk)

代码部分:

#include <bits/stdc++.h>#define LL long long#define FOR(i,x,y)  for(int i = x;i < y;++ i)#define IFOR(i,x,y) for(int i = x;i > y;-- i)using namespace std;const LL Mod = 998244353;const int maxn = 1000010;LL quickpow(LL a,int n,LL m){    LL ans=1;    while(n){        if(n&1) ans = (ans*a)%m;        a = (a*a)%m;        n>>=1;    }    return ans;}LL c[maxn];//预处理出2^n次方//cnt[x]表示x|a[i]的个数int prime[maxn],mu[maxn],cnt[maxn];bool check[maxn];void Mobius(){    memset(check,false,sizeof(check));    prime[0] = 0;    mu[1] = 1;    FOR(i,2,maxn){        if(!check[i]){            prime[++prime[0]] = i;            mu[i] = -1;        }        FOR(j,1,prime[0]+1){            if(i*prime[j] >= maxn)  break;            check[i*prime[j]] = true;            if(i % prime[j]){                mu[i*prime[j]] = -mu[i];            }            else{                mu[i*prime[j]] = 0;                break;            }        }    }    c[0] = 1;    FOR(i,1,maxn){        c[i] = c[i-1]<<(1LL);        c[i] %= Mod;    }}//F[d]表示d|gcd(b1,b2,...,bp)的个数//f[d]表示d=gcd(b1,b2,...,bp)的个数LL F[maxn],f[maxn];int n,k,mx;void init(){    scanf("%d%d",&n,&k);    memset(cnt,0,sizeof(cnt));    memset(F,0,sizeof(F));    memset(f,0,sizeof(f));    int num;    mx = -1;    FOR(i,0,n){        scanf("%d",&num);        mx = max(mx,num);        cnt[num] ++;    }    FOR(i,1,mx+1){        for(int j = i+i;j <= mx;j += i){            cnt[i] += cnt[j];        }        F[i] = (c[cnt[i]]+Mod-1)%Mod;;    }    FOR(i,1,mx+1){        for(int j = i;j <= mx;j += i){            f[i] += mu[j/i]*F[j];            f[i] %= Mod;        }    }}void work(){    LL ans = 0;    FOR(i,1,mx+1){        if(!f[i])   continue;        LL res = (f[i] * quickpow(i,k,Mod))%Mod;        ans += res;        ans %= Mod;    }    printf("%lld\n",ans);}int main(){    //freopen("test.in","r",stdin);    Mobius();    int T;  scanf("%d",&T);    while(T--){        init();        work();    }    return 0;}
0 0
原创粉丝点击