zoukankan      html  css  js  c++  java
  • 数学:莫比乌斯反演

    首先介绍一下莫比乌斯函数的形式

    1.    当d=1d=1时,μ(d)=1
    2.    当d=p1*p2*p3*…*pk且pi为互异素数时,μ(d)=(−1)^k。(说直白点,就是d分解质因数后,没有幂次大于平方的质因子,此时函数值根据分解的个数决定)
    3.    只要当d含有任何质因子的幂次大于2,则函数值为0

    在线性筛(欧拉筛法)的基础之上稍加修改就可以得到筛莫比乌斯函数的,函数

     1 #include<cstdio>
     2 const int maxn=105;
     3 int cnt;
     4 bool vis[maxn];
     5 int mu[maxn],prim[maxn];
     6 void get_mu(int n)
     7 {
     8     mu[1]=1;
     9     for(int i=2;i<=n;i++)
    10     {
    11         if(!vis[i]) {prim[++cnt]=i;mu[i]=-1;}
    12         for(int j=1;j<=cnt&&prim[j]*i<=n;j++)
    13         {
    14             vis[prim[j]*i]=1;
    15             if(i%prim[j]==0) break;
    16             else mu[i*prim[j]]=-mu[i];
    17         }
    18     }
    19 }
    20 int main()
    21 {
    22     get_mu(100);
    23     for(int i=1;i<=100;i++)
    24         printf("%d ",mu[i]);
    25     return 0;
    26 }

     

    还有其变式形式:

    据说这种形式更加常用哦

    BZOJ2301,它的题意是这样的,

    对于给出的 n 个询问,每次求有多少个数对(x,y),满足 a≤x≤b, c≤y≤d,且 gcd(x,y) = k,

    gcd(x,y)函数为 x 和 y 的最大公约数

    设calc(n,m)表示在1<=x<=n,1<=y<=m,满足gcd(x,y)是k的(x,y)的对数

    那么当限定区间在(a,b)和(c,d)的时候,可以根据容斥原理确定出来

     calc(b,d)−calc(a−1,d)−calc(b,c−1)+calc(a−1,c−1)

    那么对于求每一个calc(x,y)

    首先要明确的是求gcd(x,y)=k就是求gcd(x/k,y/k)=1的解

    然后设f(i)为gcd(x,y)=i时(x,y)的对数,F(i)表示满足i|gcd(x,y)的(x,y)的对数,显然F(i)=[n/i][m/i] 这里[]就是向下取整

    F函数很容易求得,然后我们用莫比乌斯反演公式来求那个f函数就好了

    然后在计算向下取整的时候,需要用到一个整除分块的东西提高效率

     1 #include<cstdio>
     2 #include<algorithm>
     3 using namespace std;
     4 const int maxn=50005;
     5 int tot;
     6 bool mark[maxn];
     7 int sum[maxn],mu[maxn],pri[maxn];
     8 inline int read()
     9 {
    10     int x=0,f=1;char ch=getchar();
    11     while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    12     while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    13     return x*f;
    14 }
    15 void getmu()
    16 {
    17     mu[1]=1;
    18     for(int i=2;i<=50000;i++)
    19     {
    20         if(!mark[i]) {mu[i]=-1;pri[++tot]=i;}
    21         for(int j=1;j<=tot&&i*pri[j]<=50000;j++)
    22         {
    23             mark[i*pri[j]]=1;
    24             if(i%pri[j]==0) {mu[i*pri[j]]=0;break;}
    25             else mu[i*pri[j]]=-mu[i];
    26         }
    27     }
    28     for(int i=1;i<=50000;i++)
    29         sum[i]=sum[i-1]+mu[i];
    30 }
    31 int cal(int n,int m)
    32 {
    33     if(n>m) swap(n,m);
    34     int ans=0,pos;
    35     for(int i=1;i<=n;i=pos+1)
    36     {
    37         pos=min(n/(n/i),m/(m/i));
    38         ans+=(sum[pos]-sum[i-1])*(n/i)*(m/i);
    39     }
    40     return ans;
    41 }
    42 int main()
    43 {
    44     int T;
    45     int a,b,c,d,k;
    46     getmu();
    47     T=read();
    48     while(T--)
    49     {
    50         a=read();b=read();c=read();d=read();k=read();
    51         a--;c--;
    52         a/=k;b/=k;c/=k;d/=k;
    53         int ans=cal(a,c)+cal(b,d)-cal(a,d)-cal(b,c);
    54         printf("%d
    ",ans);
    55 }
    56     return 0;
    57 }
  • 相关阅读:
    json
    ajax
    oracle 分页查询
    NuGet使用
    【EF】Entity Framework使用
    【mssql】增删改查笔记
    【mysql】知识点
    【angularJS】学习笔记
    C# Ninject使用
    【CSS】Table样式
  • 原文地址:https://www.cnblogs.com/aininot260/p/9573650.html
Copyright © 2011-2022 走看看