hdu 6053 TrickGCD (莫比乌斯)
Posted simpleknight
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了hdu 6053 TrickGCD (莫比乌斯)相关的知识,希望对你有一定的参考价值。
题意:给你一个序列a,求序列b满足 ①1<=bi<=ai ②对于序列b[l,r] gcd(bl,...,br)>=2的序列数是多少
思路:显然这道需要我们枚举gcd
设F(d)是序列b满足gcd是d的倍数的个数
F(d)的结果显而易见为∏a[i]/d
根据容斥原理ans=F(2)+F(3)+F(5)-F(6)+F(7)-F(10).....
根据莫比乌斯,我们可以把它写成ans=∑d-u(d)∏a[i]/d
log(n^2)的时间复杂度太高,我们需要进行分块处理
设f(i,d)是数组a中a/d=i的个数
那么ans=∑d=2-u(d)∏i=1if(i,d),再利用快速幂计算
时间复杂度降为log(n*log(n)^2)
代码:
#include <iostream> #include <cstring> #include <cstdio> #include <cmath> #include <algorithm> #define ll long long using namespace std; const ll mod = 1e9+7; const ll maxn = 2e5+10; bool check[maxn]; ll prime[maxn],mu[maxn],sum[maxn]; ll data[maxn],cnt[maxn]; void Moblus() { memset(check,false,sizeof(check)); mu[1]=1; int tot=0; for(int i=2;i<maxn;i++) { if(check[i]==false) { 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 qmod(ll a,ll b) { ll ans=1; a=a%mod; while(b) { if(b&1) { ans=(ans*a)%mod; } b=b/2; a=(a*a)%mod; } return ans; } int main() { int t,cas=1,n; Moblus(); cin>>t; while(t--) { cin>>n; ll minn=maxn+10; ll maxx=-1; memset(cnt,0,sizeof(cnt)); memset(sum,0,sizeof(sum)); for(int i=1;i<=n;i++) { scanf("%d",&data[i]); minn=min(data[i],minn); maxx=max(data[i],maxx); cnt[data[i]]++; } for(int i=1;i<maxn;i++) { sum[i]=sum[i-1]+cnt[i]; } ll ans=0; for(ll i=2;i<=minn;i++) { ll tmp=1; for(ll j=1;j*i<=maxx;j++) { tmp=tmp*qmod(j,sum[i*j+i-1]-sum[i*j-1])%mod; } ans=(ans-mu[i]*tmp+mod)%mod; } cout<<"Case #"<<cas++<<": "<<ans<<endl; } }
以上是关于hdu 6053 TrickGCD (莫比乌斯)的主要内容,如果未能解决你的问题,请参考以下文章