重新学习了一遍莫比乌斯反演,整理一下。
莫比乌斯函数
莫比乌斯函数是一个积性函数。
$x1.x=1\mu(x)=12.x\mu(x)=(-1)^kkx3.\mu(x)=0$
莫比乌斯函数是个积性函数,所以可以线性筛。
性质
$2.$
线性筛莫比乌斯函数代码
for(int i = 2;i <= END;++i) { if(!vis[i]) { mu[i] = -1; dis[++js] = i; } for(int j = 1;j <= js && dis[j] * i <= END;++j) { vis[i * dis[j]] = 1; if(i % dis[j]) mu[i * dis[j]] = -mu[i]; else { mu[i * dis[j]] = 0; break; } } }
莫比乌斯反演
其实莫比乌斯反演就是两个公式
设和是定义在非负整数上的两个函数
莫比乌斯反演仅仅靠这两个公式是很难做题的,做完后面两道例题应该就算入门了
公式一
若和满足
$$
公式二
若和满足
$$
证明
留坑待填吧
题目
例题1
求出有多少满足且
评测戳这里
这是非常基础的一道题目。为了便于讨论,我们下面都假定
我们设表示的数量,表示的数量
显然有下面的式子
$f(k)BDkf(1)B=\frac{B}{k},D=\frac{D}{k}F(d)O(B)x,yB$的情况,所以最后在减去就行了。
代码如下
/* * @Author: wxyww * @Date: 2019-02-22 11:00:34 * @Last Modified time: 2019-02-22 11:24:13 */ #include<cstdio> #include<iostream> #include<cstdlib> #include<cstring> #include<algorithm> #include<queue> #include<vector> #include<ctime> using namespace std; typedef long long ll; #define int ll const int N = 100000 + 100; ll read() { ll x=0,f=1;char c=getchar(); while(c<'0'||c>'9') { if(c=='-') f=-1; c=getchar(); } while(c>='0'&&c<='9') { x=x*10+c-'0'; c=getchar(); } return x*f; } int mu[N],dis[N],vis[N]; void pre() { mu[1] = 1; int js = 0; int END = 100000; for(int i = 2;i <= END;++i) { if(!vis[i]) { mu[i] = -1; dis[++js] = i; } for(int j = 1;j <= js && dis[j] * i <= END;++j) { vis[i * dis[j]] = 1; if(i % dis[j]) mu[i * dis[j]] = -mu[i]; else { mu[i * dis[j]] = 0; break; } } } } int solve(int x,int y) { int ans = 0; for(int i = 1;i <= min(x,y);++i) ans += mu[i] * (x / i) * (y / i); return ans; } signed main() { int T = read(); pre(); for(int i = 1;i <= T;++i) { read();int n = read();read();int m = read();int K = read(); int z = min(n,m); if(K != 0) printf("Case %lld: %lld\n",i,solve(n / K,m / K) - solve(z / K,z / K) / 2); else printf("Case %lld: 0\n",i); } return 0; }
例题2
直接看原题面吧
首先一个明显的转化就是,转化成对于一个数字,有多少满足。然后对于每个,计算答案就行了。
发现上面这个式子不就是上面那道题么。同样设
我们设表示时的答案。斐波那契数列第项那么这道题最终的答案就是。$T=id\prod\limits_{T=1}^n...^{\lfloor\frac{n}{T}\rfloor\lfloor\frac{m}{T}\rfloor}\sqrt{m}\prod\limits_{d|T}fb_d^{\mu(T/d)}nlog$的(调和级数)。
代码如下
/* * @Author: wxyww * @Date: 2019-02-22 15:09:25 * @Last Modified time: 2019-02-24 08:45:10 */ #include<cstdio> #include<iostream> #include<cstdlib> #include<cstring> #include<algorithm> #include<queue> #include<vector> #include<ctime> using namespace std; typedef long long ll; #define int ll const int N = 1000000 + 10,mod = 1e9 + 7; ll read() { ll x=0,f=1;char c=getchar(); while(c<'0'||c>'9') { if(c=='-') f=-1; c=getchar(); } while(c>='0'&&c<='9') { x=x*10+c-'0'; c=getchar(); } return x*f; } int f[N],mu[N],dis[N],vis[N],g[N]; int qm(ll x,int y) { int ret = 1; if(y < 0) y += mod - 1; for(;y;y >>= 1,x = 1ll * x * x % mod) if(y & 1) ret = 1ll * ret * x % mod; return ret; } int tmp[5]; void pre() { int END = 1000000; mu[1] = 1; f[1] = 1,g[0] = 1; g[1] = 1; int js = 0; for(int i = 2;i <= END;++i) { f[i] = f[i - 1] + f[i - 2]; g[i] = 1; f[i] >= mod ? f[i] -= mod : 0; if(!vis[i]) { dis[++js] = i; mu[i] = -1; } for(int j = 1;j <= js && dis[j] * i <= END;++j) { vis[i * dis[j]] = 1; if(i % dis[j]) mu[i * dis[j]] = -mu[i]; else break; } } for(int i = 1;i <= END;++i) { tmp[0] = qm(f[i],-1); tmp[1] = 1; tmp[2] = f[i]; for(int j = i;j <= END;j += i) g[j] = 1ll * g[j] * tmp[mu[j / i] + 1] % mod; } for(int i = 1;i <= END;++i) g[i] = 1ll * g[i - 1] * g[i] % mod; } signed main() { pre(); int T = read(); while(T--) { int n = read(),m = read(); if(n > m) swap(n,m); int r; ll ans = 1; for(int l = 1;l <= n;l = r + 1) { r = min(n / (n / l),m / (m / l)); ans = ans * qm(g[r] * qm(g[l - 1],mod - 2) % mod , (n / l) * (m / l) % (mod - 1)) % mod; } printf("%lld\n",ans); } return 0; }