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

    这里有个博客讲的很好:http://www.cnblogs.com/chenyang920/p/4811995.html

    这里简要解释解释记录记录下笔记。

    首先明确什么是莫比乌斯反演:

    这里有一个函数$Fleft( x ight)$,并有另一个函数$Gleft( x ight)$,满足$Gleft( x ight) =sum _{d|x}Fleft( d ight)$,那我们已知$Gleft( x ight)$求$Fleft( x ight)$的过程就是莫比乌斯反演。

     具体公式为:$Fleft( x ight) =sum _{d|x}uleft( d ight) ast Gleft( dfrac {x} {d} ight)$    这里的$uleft( x ight)$可以理解成$Gleft( x ight)$的系数,来控制$Gleft( x ight)$的取值,具体可以看看上面的博客。

    $uleft( x ight)$的具体求法可用线性筛实现。

    当x可表示成偶数个质数相乘时,$uleft( x ight) =1$

    当x可表示成奇数个质数相乘时,$uleft( x ight) =-1$

    其余情况则$uleft( x ight) =0$

     1 #include<iostream>
     2 #include<cstring>
     3 #include<cstdio>
     4 #include<cstdlib>
     5 #include<cmath>
     6 #define N 10005
     7 using namespace std;
     8 bool visit[N];
     9 int n,u[N],prim[N],a,b,c,d,k,qwq,qaq,tot;
    10 long long ans;
    11 void pre(){
    12     memset(visit,false,sizeof(visit));
    13     tot=0;
    14     u[1]=1;
    15     for (int i=2;i<=N;i++){
    16         if (!visit[i]){
    17             visit[i]=true;
    18             prim[++tot]=i;
    19             u[i]=-1;
    20         }
    21         for (int j=1;j<=tot;j++){
    22             if (prim[j]*i>N) break;
    23             visit[prim[j]*i]=true;
    24             if (i%prim[j]) u[prim[j]*i]=-u[i];
    25             else break;
    26         }
    27     }
    28 }
    29 int main(){
    30     memset(u,0,sizeof(u));
    31     pre();
    32     scanf("%d",&n);
    33     while (n--){
    34         ans=0;
    35         scanf("%d%d%d",&a,&b,&k);
    36         if (a>b) swap(a,b);
    37         qwq=a/k; qaq=b/k;
    38         for (int i=1;i<=qwq;i++)
    39          ans+=(long long)u[i]*(long long)(qwq/i)*(long long)(qaq/i);
    40         printf("%lld
    ",ans);
    41     }
    42     return 0;
    43 }
    莫比乌斯反演

    这里有部分例题的讲解:http://sxysxy.org/blogs/77

    莫比乌斯反演的题目有的需要分块求解答案,前缀和维护$uleft( x ight)$,因为考虑到整除的性质,即(i~i+p-1)整除p答案都是一样的,我们可以直接计算这部分的答案。

    具体可参考洛谷上的一题:https://www.luogu.org/problem/show?pid=2522

     1 #include<iostream>
     2 #include<cstring>
     3 #include<cstdio>
     4 #include<cstdlib>
     5 #pragma GCC optamize("O3")
     6 #pragma G++ optamize("O3")
     7 #include<cmath>
     8 #define N 50005
     9 using namespace std;
    10 bool visit[N];
    11 int n,u[N],prim[N],a,b,c,d,k,qwq,qaq,qoq,qvq,tot,sum[N];
    12 long long ans;
    13 void pre(){
    14     tot=0;
    15     sum[1]=1;
    16     u[1]=1;
    17     for (int i=2;i<=N;i++){
    18         if (!visit[i]){
    19             prim[++tot]=i;
    20             u[i]=-1;
    21         }
    22         for (int j=1;j<=tot&&prim[j]*i<=N;j++){
    23             visit[prim[j]*i]=true;
    24             if (i%prim[j]) u[prim[j]*i]=-u[i];
    25             else break;
    26         }
    27         sum[i]=sum[i-1]+u[i];
    28     }
    29 }
    30 long long cale(int l,int r){
    31     long long tmp=0;
    32     if (l>r) swap(l,r);
    33     for (int i=1,go=0;i<=l;i=go+1){   
    34      go=min(l/(l/i),r/(r/i));    //从i开始最长的相等区间长度为min(l / (l / i),r / (r / i)),比如l / (l / i),设l / i = p,p表示整除时的值,那么l / p就是从i开始整除值为p的个数了
    35      tmp+=(l/i)*(r/i)*(sum[go]-sum[i-1]);
    36     }
    37     return tmp;
    38 }
    39 int main(){
    40     pre();
    41     scanf("%d",&n);
    42     while (n--){
    43         ans=0;
    44         scanf("%d%d%d%d%d",&a,&b,&c,&d,&k);
    45         qwq=b/k;qaq=(a-1)/k;qoq=d/k;qvq=(c-1)/k;
    46         for (int i=1;i<=qwq-qaq;i++)
    47          ans=cale(qwq,qoq)-cale(qwq,qvq)-cale(qaq,qoq)+cale(qaq,qvq);   //根据容斥原理
    48         printf("%lld
    ",ans);
    49     }
    50     return 0;
    51 }
    神奇的代码

    但似乎还是会超时......(或许常数过大QAQ)

  • 相关阅读:
    links[v1]
    WebSocket handshake: Unexpected response code: 404
    Spring mvc 启动 和 请求分发
    匹配括号
    js parseFloat 精度问题
    遍历查找跳格子逻辑
    Generic type test java
    java高效判断素数
    从数组中取3个数全排列
    vue-cli
  • 原文地址:https://www.cnblogs.com/Lanly/p/7352846.html
Copyright © 2011-2022 走看看