莫比乌斯函数的个人学习总结1

ACM真的不知道是否该坚持下去了。遇到的困难不是一般的多,绩点为此付出了极大代价,整天属于睡眠不够状态,但一种热爱会推动我向前吧。。。。。。。。。

言归正传吧。

说实话学这个蛋疼得很,关于这个的定理论文很少,而且描述的十分高深。我就描述一下自己的学习心得吧。这个如果直接说的话说不清楚,我就结合例子来阐述一下吧。

两个重要的公式。


例子1:hdu5297

这题算是入门的吧:题意是删除给定数字以内,可以表示成a^b形式的数字。

#include <algorithm>
#include <cstring>
#include <string>
#include <cmath>
#include <vector>
#include <map>
#define clr(x, y) memset(x, y, sizeof x)
using namespace std;
typedef long long LL;
LL n,r;
int prime[30]={-2,-3,-5,-7,-11,-13,-17,-19,-23,-29,-31,-37,-41,-43,-47,-53,-59,-61,-67};
//用负数,便于容斥时判加减
vector <int> m;
void init()
{//得到<=r的质数的各种组合的乘积
    m.clear();
    for(int i=0;abs(prime[i])<=r;i++)
    {
        int si=m.size();
        for(int j=0;j<si;j++)
        {
            if(abs(m[j]*prime[i])<=63)
                m.push_back(m[j]*prime[i]);
            printf("%d\n",m[j]*prime[i]);
        }
        m.push_back(prime[i]);
    }
}
LL cal(LL x)
{
    LL sum=0;
    int si=m.size();
    for(LL i=0;i<si;i++)
    {
        //+0.5提高精度,-1 由于1一定会减掉,所以先不计算1
        LL num=(LL)pow(x+0.5,1.0/abs(m[i]))-1;
        if(m[i]<0) sum+=num;
        else sum-=num;
    }
    return x-sum-1;
}
LL bis()
{
    //迭代计算,用temp暂存,避免算两次cal(num)
    LL num=n;
    LL temp=cal(num);
    while(temp<n)
    {
        num+=n-temp;
        temp=cal(num);
    }
    return num;
}
int main()
{
    //freopen("input.txt","r",stdin);
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%lld %lld",&n,&r);
        init();
        printf("%lld\n",bis());
    }
    return 0;
}

借用一下别人家的代码。

例子2:BZOJ 2440

n次询问,每次询问有多少个数对(x,y)满足a<=x<=b,c<=y<=d且gcd(x,y)=k
N<=5W,1<=a<=b<=5W,1<=c<=d<=5W。

首先利用容斥原理将一个询问拆分成四个,每次询问有多少个数对(x,y)满足1<=x<=n,1<=y<=m且gcd(x,y)=k
这个问题等价于询问有多少个数对(x,y)满足1<=x<=floor(n/k),1<=y<=floor(m/k)且x与y互质

这题要注意最后的公式因为取值有相同的,所以用前缀数组来算莫比乌斯数值。

同样代码奉上

#include <cstdio>  
#include <algorithm>  
using namespace std;  
const int maxn=50010;  
  
int Prime[maxn],NotPrime[maxn],mu[maxn],sum[maxn];\\prime用来记录素数的数组,notprime用来计算非素数的数组,sum前缀莫比乌斯系数之和,mu单个的莫比乌斯系数。 
int a,b,c,d,k,T;  
  
void Get_MU()  
{  
    int cnt=0;  
    mu[1]=1;  
    for (int i=2;i<=maxn;i++)  
    {  
        if (!NotPrime[i]) {Prime[cnt++]=i;mu[i]=-1;}  
        for (int j=0;j<cnt && Prime[j]*i<=maxn;j++)  
        {  
            NotPrime[i*Prime[j]]=1;  
            if (i%Prime[j]==0) break;  
            mu[i*Prime[j]]=-mu[i];  
        }  
    }  
    for (int i=1;i<=maxn;i++) sum[i]=sum[i-1]+mu[i];  
}  
  
int Calc(int n,int m)  
{  
    int ans=0,pos;  
    if (n>m) swap(n,m);  
    for (int i=1;i<=n;i=pos+1)  
    {  
        pos=min(n/(n/i),m/(m/i));  
        ans+=(sum[pos]-sum[i-1])*(n/i)*(m/i);  
    }  
    return ans;  
}  
 int main()  
{  
    Get_MU();  
    scanf("%d",&T);  
    while (T--)  
    {  
        scanf("%d%d%d%d%d",&a,&b,&c,&d,&k);a--;c--;  
        a/=k;b/=k;c/=k;d/=k;  
        printf("%d\n",Calc(b,d)+Calc(a,c)-Calc(a,d)-Calc(b,c));  
    }  
    return 0;  
}
例子3:BZOJ 2301

这题有些蛋疼需要一些数论公式的推导与证明:

点击打开链接

后续还有……(蛋疼)


你可能感兴趣的:(莫比乌斯函数的个人学习总结1)