邝斌的ACM模板(莫比乌斯反演)

来源:互联网 发布:it教育哪家好 编辑:程序博客网 时间:2024/06/05 12:02

本博客整理自邝斌的ACM模板
2.13、莫比乌斯反演
莫比乌斯反演公式:
这里写图片描述这里写图片描述
莫比乌斯函数这里写图片描述
另外一种更常用的形式:
在某一范围内:这里写图片描述这里写图片描述
线性筛法求解积性函数(莫比乌斯函数)

const int MAXN = 1000000;bool check[MAXN+10];int prime[MAXN+10];int mu[MAXN+10];void Moblus(){    memset(check,false,sizeof(check));    mu[1] = 1;    int tot = 0;    for(int i = 2; i <= MAXN; i++)    {        if( !check[i] )        {            prime[tot++] = i;            mu[i] = -1;        }        for(int j = 0; j < tot; j++)        {            if(i * prime[j] > MAXN) break;            check[i * prime[j]] = true;            if( i % prime[j] == 0)            {                mu[i * prime[j]] = 0;                break;            }            else            {                mu[i * prime[j]] = -mu[i];            }        }    }}

例题:
BZOJ 2301
对于给出的 n 个询问,每次求有多少个数对(x,y),满足 a≤x≤b, c≤y≤d,且 gcd(x,y) = k,
gcd(x,y)函数为 x 和 y 的最大公约数。
1≤n≤50000,1≤a≤b≤50000,1≤c≤d≤50000,1≤k≤50000

const int MAXN = 100000;bool check[MAXN+10];int prime[MAXN+10];int mu[MAXN+10];void Moblus(){    memset(check,false,sizeof(check));    mu[1] = 1;    int tot = 0;    for(int i = 2; i <= MAXN; i++)    {        if( !check[i] )        {            prime[tot++] = i;            mu[i] = -1;        }        for(int j = 0; j < tot; j ++)        {            if( i * prime[j] > MAXN) break;            check[i * prime[j]] = true;            if( i % prime[j] == 0)            {                mu[i * prime[j]] = 0;                break;            }            else            {                mu[i * prime[j]] = -mu[i];            }        }    }}int sum[MAXN+10];//找[1,n],[1,m]内互质的数的对数long long solve(int n,int m){    long long ans = 0;    if(n > m)swap(n,m);    for(int i = 1, la = 0; i <= n; i = la+1)    {        la = min(n/(n/i),m/(m/i));        ans += (long long)(sum[la] - sum[i-1])*(n/i)*(m/i);    }    return ans;}int main(){    Moblus();    sum[0] = 0;    for(int i = 1; i <= MAXN; i++)   sum[i] = sum[i-1] + mu[i];    int a,b,c,d,k;    int T;    scanf("%d",&T);    while(T--)    {        scanf("%d%d%d%d%d",&a,&b,&c,&d,&k);        long long ans = solve(b/k,d/k) - solve((a-1)/k,d/k) - solve(b/k,(c-1)/k) + solve((a-1)/k,(c-1)/k);        printf("%lld\n",ans);    }    return 0;}
原创粉丝点击