hdu 6053 莫比乌斯函数(容斥)

来源:互联网 发布:数据研究中心美国大学 编辑:程序博客网 时间:2024/06/11 01:06

题意:两个序列,A,B,A序列给出,Bi<=Ai,问满足所有区间的gcd l r != 1 的B序列的方案数


思路:枚举B整体的GCD,直接枚举显然会重复计算,顾使用莫比乌斯进行容斥,单组因子的方案数就是sum (ai/p)

显然直接枚举时间复杂度为n*m  m=min ai  ,在这里我们做一个桶的处理,并求后缀和,就直接计算出 ai/p =ni 的个数

知道所以的ni就可以算出sum (ai/p) ,这里处理的方法类似筛法,时间复杂度约为nlogn,加上公式中的快速幂,时间复杂度nlognlogn


代码:

#include<bits/stdc++.h>using namespace std;#define X first#define Y second#define PB push_back#define MP make_pair#define MEM(a,b) memset(a,b,sizeof(a))typedef long long ll;typedef pair<int,int> pii;const ll mod = 1e9+7;const int maxn =2e5+10;ll n,k,mi,ans,mx;ll a[maxn],T[maxn];const int MAXN = 250000;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];            }        }    }}ll qpow(ll a,ll b){    ll ret=1;    while(b){        if(b&1) ret=(ret*a)%mod;        a=(a*a)%mod;        b>>=1;    }    return ret;}int main(){    int t,ca=1;    Moblus();    scanf("%d",&t);    while(t--){        MEM(T,0);        scanf("%d",&n);        mi=1e9;ans=0;mx=-1e9;        for(int i=0;i<n;i++) scanf("%d",&a[i]),mi=min(mi,a[i]),mx=max(mx,a[i]),T[a[i]]+=1;        for(int i=maxn-5;i>0;i--) T[i]+=T[i+1];        for(ll i=2;i<=mi;i++){            ll ret=-mu[i];            ll p=i,cnt=1;            while(p<=mx) ret=(ret*qpow(cnt++,T[p]-T[p+i]))%mod,p=p+i;            ans= (ret+ans+mod+mod)%mod;        }        printf("Case #%d: %lld\n",ca++,(ans+mod)%mod);    }    return 0;}

再附上一种容斥写法

#include<bits/stdc++.h>using namespace std;#define X first#define Y second#define PB push_back#define MP make_pair#define MEM(a,b) memset(a,b,sizeof(a))typedef long long ll;typedef pair<int,int> pii;const ll mod = 1e9+7;const int maxn =1e6+10;ll n,k;ll mi,ans,mx;ll a[maxn],T[maxn];vector<int> P;const int MAXN=10000;int prime[MAXN+10];void getPrime(){    memset(prime,0,sizeof(prime));    for(int i=2; i<=MAXN; i++){        if(!prime[i])prime[++prime[0]]=i;        for(int j=1; j<=prime[0]&&prime[j]<=MAXN/i; j++){            prime[prime[j]*i]=1;            if(i%prime[j]==0) break;        }    }}ll qpow(ll a,ll b){    ll ret=1;    while(b){        if(b&1) ret=(ret*a)%mod;        a=(a*a)%mod;        b>>=1;    }    return ret;}void dfs(ll x,int p,int id){    if(x>mi) return;    if(id!=0){        ll ret=1;        ll pp=x,cnt=1;        while(pp<=mx) ret=(ret*qpow(cnt++,T[pp]-T[pp+x]))%mod,pp=pp+x;        if(p)ans=(ans+ret)%mod;        else ans=(ans-ret+mod)%mod;    }    for(int i=id+1;i<=prime[0];i++)        dfs(x*prime[i],p^1,i);}int main(){    int t,ca=1;    scanf("%d",&t);    getPrime();    while(t--){        scanf("%d",&n);        MEM(T,0);mi=1e9;ans=0;mx=-1e9;        for(int i=0;i<n;i++) scanf("%d",&a[i]),mi=min(mi,a[i]),mx=max(mx,a[i]),T[a[i]]+=1;        for(int i=maxn-5;i>0;i--) T[i]+=T[i+1];        dfs(1,0,0);        printf("Case #%d: %lld\n",ca++,(ans+mod)%mod);    }    return 0;}



原创粉丝点击