【2017多校】HDU6053 TrickGCD 【莫比乌斯】

来源:互联网 发布:搜狗搜索sem优化师 编辑:程序博客网 时间:2024/06/08 07:37

gcd(l,r)=d,b[i]{d,2d,3d,...,floor(a[i]/d)d}
gcd(l,r)=d,=ni=1a[i]d

mu[i]=1kk=i
ans=ni=1{(mu[i])nj=1a[j]i}

O(n2)

sum[i]=nj=1(a[j]<=i)
i,k,a[j]i=kjsum[(k+1)i1]sum[ki1]
gcd=i=n/ik=1ksum[(k+1)i1]sum[ki1]

ans=ni=1k=n/ik=1ksum[(k+1)i1]sum[ki1]

O(nlogn(1+12+13+...))=O(nlogn)=...O(nlogn(ln(n+1)+r))

#include<stdio.h>#include<iostream>#include<stdlib.h>#include<algorithm>#include<vector>#include<string.h>#include<string>#include<math.h>#include<memory.h>#include<queue>#define ll long long#define pii pair<int,int>#define pll pair<ll,ll>#define MEM(a,x) memset(a,x,sizeof(a))#define lowbit(x) ((x)&-(x))using namespace std;//const int inf=0x3f3f3f3f;const int MOD = 1e9+7;const int N = 1e5 + 5;const int inf=MOD;const int MAXN = 100000;bool check[MAXN+10];int prime[MAXN+10];int mu[MAXN+10];void Moblus(){    memset(check,false,sizeof(check));    mu[1] = 1;    int tot = 0;    for(int i = 2; i <= MAXN; i++)    {        if( !check[i] ){            prime[tot++] = i;            mu[i] = -1;        }        for(int j = 0; j < tot; j++)        {            if(i * prime[j] > MAXN) break;            check[i * prime[j]] = true;            if( i % prime[j] == 0){                mu[i * prime[j]] = 0;                break;            }else{                mu[i * prime[j]] = -mu[i];            }        }    }}int sum[N];int a[N];ll qPow(ll a,int n){    ll ans=1;    ll t=a%MOD;    while(n){        if(n&1){            ans=(ans*t)%MOD;        }        n>>=1;        t=(t*t)%MOD;    }    return ans;}ll w(int x,int n){    if(sum[x-1]){        return 0;    }    ll ans=1;    for(int i=1;i*x<N-1;++i){        ll t=qPow(i,sum[min((i+1)*x-1,N-1)]-sum[min(N-1,i*x-1)]);        ans=(ans*t)%MOD;    }    return ans;}ll slove(int n){    ll ans=0;    for(int i=2;i<=n;++i){        ans+=(-w(i,n)*mu[i])%MOD;        ans%=MOD;    }    return (ans+MOD)%MOD;}int main(){    //freopen("/home/lu/code/r.txt","r",stdin);    Moblus();    int T;    scanf("%d",&T);    for(int tt=1;tt<=T;++tt){        int n;        MEM(sum,0);        scanf("%d",&n);        for(int i=1;i<=n;++i){            scanf("%d",&a[i]);            ++sum[a[i]];        }        for(int i=1;i<N;++i){            sum[i]+=sum[i-1];        }        printf("Case #%d: %lld\n",tt,slove(n));    }    return 0;}