莫比乌斯函数筛法

莫比乌斯有两种反演形式:

\[\begin{array}{l}
f(n) = \sum\limits_{d|n} {u(d)F(\frac{n}{d})} \\
f(n) = \sum\limits_{n|d} {u(\frac{d}{n})F(d)}
\end{array}\]

 

最简单筛法

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 int mu[10005];
 5 int n=10000;
 6 void sieve(){
 7     mu[1]=1;
 8     for(int i=1;i<=n;i++){
 9         for(int j=2*i;j<=n;j+=i){
10             mu[j]-=mu[i];
11         }
12     }
13 }
14 int main(){
15     sieve();
16     for(int i=1;i<=100;i++){
17         cout<<mu[i]<<" ";
18     }
19 }

线性筛法:

 1 const int maxn=60000+5;
 2 bool vis[maxn];
 3 int prime[maxn],mu[maxn];
 4 void init_mu(int n){
 5     int cnt=0;
 6     mu[1]=1;
 7     for(int i=2;i<n;i++){
 8         if(!vis[i]){
 9             prime[cnt++]=i;
10             mu[i]=-1;
11         }
12         for(int j=0;j<cnt&&i*prime[j]<n;j++){
13             vis[i*prime[j]]=1;
14             if(i%prime[j]==0)   {mu[i*prime[j]]=0;break;}
15             else { mu[i*prime[j]]=-mu[i];}
16         }
17     }
18 }

 

 

《挑战程序设计》例题:没有周期性的字符串函数的计数,用约数的反演形式

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 int mu[10005];
 5 int n=10000;
 6 void sieve(){
 7     mu[1]=1;
 8     for(int i=1;i<=n;i++){
 9         for(int j=2*i;j<=n;j+=i){
10             mu[j]-=mu[i];
11         }
12     }
13 }
14 int main(){
15     sieve();
16     while(cin>>n){
17         int res=0;
18         for(int i=1;i<=n;i++){
19             if(n%i==0){
20                 res+=mu[n/i]*pow(26,i);
21             }
22         }
23         cout<<res<<endl;
24     }
25 }

 

hdu1695 gcd

解法一:转化成gcd=1,用倍数的反演形式

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 int mu[1050500];
 5 int n=1000000;
 6 void sieve(){
 7     mu[1]=1;
 8     for(int i=1;i<=n;i++){
 9         for(int j=2*i;j<=n;j+=i){
10             mu[j]-=mu[i];
11         }
12     }
13 }
14 int main(){
15     sieve();
16     ll t,a,b,c,d,k,ans1,ans2;
17     cin>>t;
18     for(int i=1;i<=t;i++){
19         ans1=ans2=0;
20         cin>>a>>b>>c>>d>>k;
21         if(b>d) swap(b,d);
22         if(k==0){
23             printf("Case %d: 0\n",i);
24             continue;
25         }
26         b/=k,d/=k;
27         for(int j=1;j<=b;j++){
28             ans1+=mu[j]*(b/j)*(d/j);
29         }
30         for(int j=1;j<=b;j++){
31             ans2+=mu[j]*(b/j)*(b/j);
32         }
33         printf("Case %d: %lld\n",i,ans1-ans2/2);
34     }
35     return 0;
36 }

 解法二:其实是一种思路,就是直接运用莫比乌斯反演公式,,只是想自己多练习一下而已。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 int mu[1050500];
 5 int n=1000000;
 6 void sieve(){
 7     mu[1]=1;
 8     for(int i=1;i<=n;i++){
 9         for(int j=2*i;j<=n;j+=i){
10             mu[j]-=mu[i];
11         }
12     }
13 }
14 int main(){
15     sieve();
16     ll t,a,b,c,d,k,ans1,ans2;
17     cin>>t;
18     for(int i=1;i<=t;i++){
19         ans1=ans2=0;
20         cin>>a>>b>>c>>d>>k;
21         if(b>d) swap(b,d);
22         if(k==0){
23             printf("Case %d: 0\n",i);
24             continue;
25         }
26         for(int j=k;j<=b;j+=k){
27             ans1+=(ll)mu[j/k]*(b/j)*(d/j);
28         }
29         for(int j=k;j<=b;j+=k){
30             ans2+=(ll)mu[j/k]*(b/j)*(b/j);//注意加括号 
31         }
32         printf("Case %d: %lld\n",i,ans1-ans2/2);
33     }
34     return 0;
35 }

 

posted @ 2017-07-28 19:04  Elpsywk  阅读(1853)  评论(0编辑  收藏  举报