莫比乌斯函数筛法

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

\[\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 }

 

转载于:https://www.cnblogs.com/elpsycongroo/p/7252171.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值