hdu 6053 莫比烏斯函式(容斥)
阿新 • • 發佈:2019-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; }