【HDU6134】Battlestation Operational (莫比乌斯反演)

来源:互联网 发布:mac终端返回上级目录 编辑:程序博客网 时间:2024/06/01 09:31

多校第八场没想到碰到了一直想学却没有学的莫比乌斯反演,比赛时不出意外的打出了gg,便下定决心要好好会一会高深的莫比乌斯反演(在菜鸡的眼里是这样),下面是我的一些学习资料:

http://www.cnblogs.com/chenyang920/p/4811995.html

http://blog.csdn.net/acdreamers/article/details/8542292

https://wenku.baidu.com/view/fbec9c63ba1aa8114431d9ac.html


看完这些之后不得不佩服这些数学家的伟大,这个算法对于解决组合问题,包含gcd的条件的问题实在太厉害了。


然后就要开始讲这道题目了,这场的多校赛题目都是巨长,我就大概说一下这道题的题意

题目给出一个n*n的矩阵对于矩阵中每一个点(x, y) 如果x >= y && gcd(x, y) = 1, 那么这个点的值为 x / y 向上取整, 否则就为0,要求这个矩阵的各个点的值的总和。即如公式所见:


分析:

首先设

因为gcd(i, j)等于1才有效,因此i / j 一定无法整除(除了j = 1),且结果就为 i / j + 1,因此有如下转化,其中φ(i)为欧拉函数


然后就是重要发现:



然后运用莫比乌斯反演


可得:



继续转化:


其中τ(n)表示n的约数个数,是积性函数也可以线性求出


其实后来发现:

F(n) = F(n - 1) + d(n - 1) + 1, 其中d(n)表示n的约数的个数

这样可以递推出每一项的F(n),

然后利用莫比乌斯反演公式就可以求出每一项f(n),注意这里求每一项的f(n)可以枚举j, 然后j的倍数的答案可以很容易求出,因为调和级数这样复杂度为nlog(n), f(n)的前缀和就是答案

#include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <map>#include <set>#include <vector>#include <queue>#include <cmath>#include <bitset>using namespace std;const int M = 1e9 + 7;const int MAXN = 1000005;int g[MAXN], pre[MAXN];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 <= 1000000; 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 factor[100][2];int getFactors(int x){    int fatCnt = 0;    int tmp = x;    for(int i = 0; prime[i] <= tmp / prime[i];i++)    {        factor[fatCnt][1] = 0;        if(tmp%prime[i] == 0)        {            factor[fatCnt][0] = prime[i];            while(tmp%prime[i] == 0)            {                factor[fatCnt][1]++;                tmp /= prime[i];            }            fatCnt++;        }    }    if(tmp != 1)    {        factor[fatCnt][0] = tmp;        factor[fatCnt++][1] = 1;    }    return fatCnt;}int main(){    Moblus();    g[1] = 1;    int cnt = 1;    for(int i = 2; i <= 1000000; ++i)    {        g[i] = g[i - 1] + cnt + 1;        int m = getFactors(i);        cnt = 1;        for(int j = 0; j < m; ++j)             cnt *= (factor[j][1] + 1);    }    for(int j = 1; j <= 1000000; ++j)        for(int k = j, t = 1; k <= 1000000; k += j, t++)            pre[k] += mu[t] * g[j];    for(int i = 2; i <= 1000000; ++i)        pre[i] = (pre[i] + pre[i - 1]) % M;    int n;    while(scanf("%d", &n) != EOF)    {        printf("%d\n", pre[n]);    }    return 0;}


然后这里还附一份我觉得更简洁的代码:

#include<cstdio>#include<cstring>#include<vector>using namespace std;typedef long long int ll;const ll mod = 1e9 + 7;const int A = 1e6 + 10;int mu[A],pri[A],tot;ll d[A],cnt[A],sum[A];bool vis[A];void init(){    tot = 0;mu[1] = d[1] = 1;    for(int i=2 ;i<A ;i++){        if(!vis[i]){mu[i] = -1;pri[++tot] = i;d[i] = 2;cnt[i] = 1;}        for(int j=1 ;j<=tot && pri[j]*i<A ;j++){            vis[i*pri[j]] = 1;            if(i%pri[j] == 0){                d[i*pri[j]] = d[i]/(cnt[i]+1)*(cnt[i]+2);                cnt[i*pri[j]] = cnt[i] + 1;                mu[i*pri[j]] = 0;                break;            }            d[i*pri[j]] = d[i]<<1;            cnt[i*pri[j]] = 1;            mu[i*pri[j]] = -mu[i];        }    }    sum[1] = 1;    for(int i=2 ;i<A ;i++){        sum[i] = (sum[i-1] + d[i-1] + 1)%mod;    }    for(int i=1 ;i<A ;i++){        sum[i] = (sum[i] + sum[i-1])%mod;        mu[i] = (mu[i] + mu[i-1])%mod;    }}int main(){    init();    int n;    while(~scanf("%d",&n)){        ll ans = 0;        int last;        for(int i=1 ;i<=n ;i=last + 1){            last = n/(n/i);            ans = (ans + (mu[last]-mu[i-1])%mod*(sum[n/i])%mod)%mod;        }        ans = (ans%mod + mod)%mod;        printf("%I64d\n",ans);    }    return 0;}


阅读全文
0 0
原创粉丝点击