莫比乌斯函数 && HDU-1695
莫比乌斯函数定义:
$$\mu(d)=\begin{cases}
1 &\text{d = 1}\\
(-1)^r &\text{$d=p_1p_2...p_r,其中p_i为不同的素数$}\\
0 &\text{else}
\end{cases}$$
性质:
(1)$\sum_{d|n}\mu(d)=[n=1]$
(2)$\sum_{d|n}\frac{\mu(d)}{d}=\frac{\phi(n)}{n}$
莫比乌斯反演(没写定义域之类的):
$F(n)=\sum_{d|n}f(d)或F(n)=\sum_{d|n}f(\frac{n}{d}){\quad}{\Leftrightarrow}{\quad}f(n)=\sum_{d|n}\mu(d)F(\frac{n}{d})或f(n)=\sum_{d|n}\mu(\frac{n}{d})F(d)$
$F(n)=\sum_{n|d}f(d){\quad}{\Leftrightarrow}{\quad}f(n)=\sum_{n|d}\mu(\frac{d}{n})F(d)$(一般用的都是这种)
并不清楚为什么d没有上限
证明:https://wenku.baidu.com/view/fbec9c63ba1aa8114431d9ac.html
(性质1根据二项式定理直接证,那么反演公式可以根据性质1证(第二种反演的证法类似第一种反演,式子可以做类似的变换))
线性筛莫比乌斯函数
设mu[i]为i的莫比乌斯函数值
首先,mu[1]=1
mu[一个质数]=-1
对于一个合数x,设其最小质因子为p,那么它会被q=x/p筛掉,在它被q筛掉时,判断一下q%p是否为0,如果为0则说明q有至少1个质因子p,因此x有至少2个质因子p,那么mu[x]=0;否则mu[x]=-mu[q]
模板题:给定i,j,k,求$\sum_{i=1}^n{\sum_{j=1}^m{[(i,j)=k]}}$
设$f(x)=\sum_{i=1}^n{\sum_{j=1}^m{[(i,j)=x]}}$
设$F(x)=\sum_{x|d}{\sum_{i=1}^n{\sum_{j=1}^m{[(i,j)=d]}}}=\sum_{i=1}^n{\sum_{j=1}^m{[x|(i,j)]}}$
显然$F(x)={\lfloor}{\frac{n}{x}}{\rfloor}*{\lfloor}{\frac{m}{x}}{\rfloor}$
那么可以根据F(x)计算f(x)得到答案
(从中看出一类通用的关系:"满足f(a)是x的倍数/因数的a个数""满足f(a)等于x的a的个数"间的转换)
https://vjudge.net/problem/HDU-1695
(此题跟以上"模板题"题面类似,但不完全一样,要加一些特判)
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #include<vector> 5 using namespace std; 6 #define fi first 7 #define se second 8 #define mp make_pair 9 #define pb push_back 10 typedef long long ll; 11 typedef unsigned long long ull; 12 typedef pair<int,int> pii; 13 #define N 100100 14 ll prime[N+100],len,mu[N+100]; 15 bool nprime[N+100]; 16 ll a,c,n,m,k,ans,a2; 17 ll F(ll x) {return (m/x)*(n/x);} 18 ll F2(ll x) {return (n/x)*(n/x);} 19 int main() 20 { 21 ll i,j,T,TT; 22 mu[1]=1; 23 for(i=2;i<=N;i++) 24 { 25 if(!nprime[i]) prime[++len]=i,mu[i]=-1; 26 for(j=1;j<=len&&i*prime[j]<=N;j++) 27 { 28 nprime[i*prime[j]]=1; 29 if(i%prime[j]==0) {mu[i*prime[j]]=0;break;} 30 else mu[i*prime[j]]=-mu[i]; 31 } 32 } 33 scanf("%lld",&T); 34 for(TT=1;TT<=T;TT++) 35 { 36 scanf("%lld%lld%lld%lld%lld",&a,&n,&c,&m,&k); 37 if(n>m) swap(n,m); 38 ans=a2=0; 39 if(k>n||k==0) goto xxx; 40 for(i=1;i<=n/k;i++) 41 ans+=mu[i]*F(i*k); 42 for(i=1;i<=n/k;i++) 43 a2+=mu[i]*F2(i*k); 44 ans-=(a2-1)/2; 45 xxx:; 46 printf("Case %lld: %lld\n",TT,ans); 47 } 48 return 0; 49 }
另外:此题也可以不用莫比乌斯函数做,可以直接容斥
简单来讲就是先算出数组F,其中F[i]=F(i)
然后预处理出n个vector(d1,d2,..,dn),第i个表示i的所有因子(用枚举每个数的倍数的方式,而不是枚举因子)
然后从大到小枚举i,对于i除自身外所有的因子j,F[j]-=F[i]
对此题并没有什么特别的好处。。只是记一下有这种方法
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #include<vector> 5 using namespace std; 6 #define fi first 7 #define se second 8 #define mp make_pair 9 #define pb push_back 10 typedef long long ll; 11 typedef unsigned long long ull; 12 typedef pair<int,int> pii; 13 #define N 100100 14 ll an[N+100]; 15 ll a,c,n,m,k,ans,a2; 16 ll F(ll x) {return (m/x)*(n/x);} 17 ll F2(ll x) {return (n/x)*(n/x);} 18 vector<ll> d[100100]; 19 int main() 20 { 21 ll i,j,T,TT; 22 for(i=1;i<=100000;i++) 23 for(j=2*i;j<=100000;j+=i) 24 d[j].pb(i); 25 scanf("%lld",&T); 26 for(TT=1;TT<=T;TT++) 27 { 28 scanf("%lld%lld%lld%lld%lld",&a,&n,&c,&m,&k); 29 if(n>m) swap(n,m); 30 ans=a2=0; 31 if(k>n||k==0) goto xxx; 32 for(i=1;i<=n;i++) an[i]=F(i); 33 for(i=n;i>=1;i--) 34 for(j=0;j<d[i].size();j++) 35 an[d[i][j]]-=an[i]; 36 ans+=an[k]; 37 for(i=1;i<=n;i++) an[i]=F2(i); 38 for(i=n;i>=1;i--) 39 for(j=0;j<d[i].size();j++) 40 an[d[i][j]]-=an[i]; 41 a2+=an[k]; 42 ans-=(a2-1)/2; 43 xxx:; 44 printf("Case %lld: %lld\n",TT,ans); 45 } 46 return 0; 47 }
资料待看: