[BZOJ3994][SDOI2015]约数个数和(莫比乌斯反演)
2017-10-18 23:33
357 查看
首先介绍一个性质:∑Ni=1∑Mj=1σ0(ij)=∑Ni=1∑Mj=1⌊Ni⌋⌊Mj⌋[gcd(i,j)=1]。
证明为:
先设上式等号左边为f(N,M),等号右边为g(N,M)。
则有:
f(N,M)−f(N−1,M)−f(N,M−1)+f(N−1,M−1)=σ0(NM)
g(N,M)−g(N−1,M)−g(N,M−1)+g(N−1,M−1)
=∑i∑j(⌊Ni⌋−⌊N−1i⌋)(⌊Mj⌋−⌊M−1j⌋)[gcd(i,j)=1]
可以知道,⌊Ni⌋−⌊N−1i⌋=1当且仅当i|N,⌊Mj⌋−⌊M−1j⌋同理。
也就是说,g(N,M)−g(N−1,M)−g(N,M−1)+g(N−1,M−1)就相当于求∀1≤i≤N,1≤j≤M,满足i|N,j|M,gcd(i,j)=1的数对(i,j)的个数。实际上,这个值等于σ0(NM)。
Q:为什么上面这样做就不会重复枚举约数呢?
A:设k=Ni。如果存在一个kj=ab,a|k,a|N,b|M,则再设k=ax,就有ijx2=Na∗b,又由于此时又有b=jx,所以这时候Na和b一定含有公约数x,即不互质。从上面得出,满足i|N,j|M,gcd(i,j)=1并且Ni∗j为定值的数对只有1个。得证。
得出式子:
Ans=∑Ni=1∑Mj=1⌊Ni⌋⌊Mj⌋[gcd(i,j)=1]
=∑Ni=1∑Mj=1⌊Ni⌋⌊Mj⌋∑d|gcd(i,j)μ(d)
=∑d∑Ni=1,d|i∑Mj=1,d|j⌊Ni⌋⌊Mj⌋μ(d)
=∑dμ(d)∑⌊Nd⌋i=1∑⌊Md⌋j=1⌊Nid⌋⌊Mjd⌋
=∑dμ(d)(∑⌊Nd⌋i=1⌊⌊Nd⌋i⌋)∗(∑⌊Md⌋j=1⌊⌊Md⌋j⌋)。
可以O(nn−−√)预处理出∑xi=1⌊xi⌋的值后,分块解决。
总之,莫比乌斯反演的关键是利用好∑d|nμ(d)=[n=1]这个公式,并把⌊Ni⌋的值分块。
代码:
证明为:
先设上式等号左边为f(N,M),等号右边为g(N,M)。
则有:
f(N,M)−f(N−1,M)−f(N,M−1)+f(N−1,M−1)=σ0(NM)
g(N,M)−g(N−1,M)−g(N,M−1)+g(N−1,M−1)
=∑i∑j(⌊Ni⌋−⌊N−1i⌋)(⌊Mj⌋−⌊M−1j⌋)[gcd(i,j)=1]
可以知道,⌊Ni⌋−⌊N−1i⌋=1当且仅当i|N,⌊Mj⌋−⌊M−1j⌋同理。
也就是说,g(N,M)−g(N−1,M)−g(N,M−1)+g(N−1,M−1)就相当于求∀1≤i≤N,1≤j≤M,满足i|N,j|M,gcd(i,j)=1的数对(i,j)的个数。实际上,这个值等于σ0(NM)。
Q:为什么上面这样做就不会重复枚举约数呢?
A:设k=Ni。如果存在一个kj=ab,a|k,a|N,b|M,则再设k=ax,就有ijx2=Na∗b,又由于此时又有b=jx,所以这时候Na和b一定含有公约数x,即不互质。从上面得出,满足i|N,j|M,gcd(i,j)=1并且Ni∗j为定值的数对只有1个。得证。
得出式子:
Ans=∑Ni=1∑Mj=1⌊Ni⌋⌊Mj⌋[gcd(i,j)=1]
=∑Ni=1∑Mj=1⌊Ni⌋⌊Mj⌋∑d|gcd(i,j)μ(d)
=∑d∑Ni=1,d|i∑Mj=1,d|j⌊Ni⌋⌊Mj⌋μ(d)
=∑dμ(d)∑⌊Nd⌋i=1∑⌊Md⌋j=1⌊Nid⌋⌊Mjd⌋
=∑dμ(d)(∑⌊Nd⌋i=1⌊⌊Nd⌋i⌋)∗(∑⌊Md⌋j=1⌊⌊Md⌋j⌋)。
可以O(nn−−√)预处理出∑xi=1⌊xi⌋的值后,分块解决。
总之,莫比乌斯反演的关键是利用好∑d|nμ(d)=[n=1]这个公式,并把⌊Ni⌋的值分块。
代码:
#include <cmath> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; inline int read() { int res = 0; bool bo = 0; char c; while (((c = getchar()) < '0' || c > '9') && c != '-'); if (c == '-') bo = 1; else res = c - 48; while ((c = getchar()) >= '0' && c <= '9') a681 res = (res << 3) + (res << 1) + (c - 48); return bo ? ~res + 1 : res; } typedef long long ll; const int MaxN = 5e4, N = MaxN + 5; int miu , pri , tot, sum , Sum ; bool mark ; void sieve() { int i, j; miu[1] = 1; mark[0] = mark[1] = 1; for (i = 2; i <= MaxN; i++) { if (!mark[i]) pri[++tot] = i, miu[i] = -1; for (j = 1; j <= tot; j++) { if (1ll * i * pri[j] > MaxN) break; mark[i * pri[j]] = 1; if (i % pri[j] == 0) break; else miu[i * pri[j]] = -miu[i]; } } for (i = 1; i <= MaxN; i++) sum[i] = sum[i - 1] + miu[i]; for (i = 1; i <= MaxN; i++) for (j = 1; j <= i;) { int nxt = i / (i / j); Sum[i] += i / j * (nxt - j + 1); j = nxt + 1; } } ll solve(int a, int b) { int i, n = min(a, b); ll ans = 0; for (i = 1; i <= n;) { int nxt = min(a / (a / i), b / (b / i)); ans += 1ll * Sum[a / i] * Sum[b / i] * (sum[nxt] - sum[i - 1]); i = nxt + 1; } return ans; } int main() { int a, b, T = read(); sieve(); while (T--) a = read(), b = read(), printf("%lld\n", solve(a, b)); return 0; }
相关文章推荐
- 【BZOJ3994】【SDOI2015】约数个数和(莫比乌斯反演)
- 【BZOJ 3994】3994: [SDOI2015]约数个数和(莫比乌斯反演)
- 【BZOJ3994】【SDOI2015】约数个数和(莫比乌斯反演)
- [BZOJ3994][SDOI2015]约数个数和(莫比乌斯反演)
- [BZOJ3994][SDOI2015]约数个数和(莫比乌斯反演)
- 【SDOI2015】【BZOJ3994】约数个数和
- BZOJ 3994 [SDOI2015]约数个数和
- BZOJ3994: [SDOI2015]约数个数和
- BZOJ3994: [SDOI2015]约数个数和
- [bzoj3994][SDOI2015]约数个数和
- 【bzoj3994】[SDOI2015]约数个数和 线性筛法+莫比乌斯反演+数论分块
- bzoj 3994: [SDOI2015]约数个数和
- BZOJ 3994: [SDOI2015]约数个数和
- [bzoj 3994] sdoi2015 约数个数和
- BZOJ 3994 [SDOI2015]约数个数和
- bzoj 3994 [SDOI2015]约数个数和
- bzoj 3994 [SDOI2015]约数个数和
- [BZOJ 3994][SDOI 2015]约数个数 数学+反演
- bzoj3994[SDOI2015]约数个数和
- 【bzoj3994】[SDOI2015]约数个数和 莫比乌斯反演