[BZOJ3529][SDOI2014]数表(莫比乌斯反演+树状数组)

来源:互联网 发布:gtx1050ti 知乎 编辑:程序博客网 时间:2024/06/08 12:56

1、概述

莫比乌斯反演。首先,预处理出f[i]=d|id

2、先不考虑a的限制

可以推出,
ans=ni=1mj=1f[gcd(i,j)]
=df[d]ni=1mj=1[gcd(i,j)=d]
=df[d]ndi=1mdi=1[gcd(i,j)=1]
=df[d]ndi=1mdi=1k|gcd(i,j)μ(k)
=df[d]kndi=1,k|imdj=1,k|jμ(k)
=df[d]kndkmdkμ(k)
u=dk,则原式化为
unumud|uf[d]μ(ud)
d|uf[d]μ(ud)的值和前缀和预处理之后就可以分块做,O(n)解决一组询问了。

3、再考虑a的限制

可以想到,对于任何f[d]>ad,就当f[d]=0考虑。而在询问时要不断地更新f[d]的值,于是想到离线,即将每个询问按照a排序,这样就可以保证每个f[d]只被更新一次,d|uf[d]μ(ud)的值的更新也是复杂度可以承受的。
考虑到d|uf[d]μ(ud)的前缀和无法立即更新,所以要用树状数组维护d|uf[d]μ(ud)的值。

4、代码

#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')        res = (res << 3) + (res << 1) + (c - 48);    return bo ? ~res + 1 : res;}const int MaxN = 1e5, N = MaxN + 5, M = 403205;bool mark[N]; int Q, miu[N], T[M], pri[N], tot, L[M], R[M], ans[N];void change(int x, int v) {    for (; x <= MaxN; x += x & -x)        T[x] += v;}int ask(int x) {    int res = 0;    for (; x; x -= x & -x)        res += T[x];    return res;}struct cyx {int id, val;} f[MaxN];struct pyz {int id, n, m, a;} q[MaxN];inline bool ccyx(const cyx &a, const cyx &b) {    return a.val < b.val;}inline bool cpyz(const pyz &a, const pyz &b) {    return a.a < b.a;}void sieve() {    int i, j; mark[0] = mark[1] = 1; miu[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++) {        f[i].id = i; for (j = i; j <= MaxN; j += i)            f[j].val += i;    }    sort(f + 1, f + MaxN + 1, ccyx);    for (i = 1; i <= MaxN;) {        L[f[i].val] = j = i;        for (; f[i].val == f[j].val; j++);        R[f[i].val] = j - 1; i = j;    }}void addD(int x) {    if (!L[x]) return;    int i, j, k; for (i = L[x]; i <= R[x]; i++) {        k = 0; int u = f[i].id; for (j = u; j <= MaxN; j += u)            change(j, x * miu[++k]);    }}int queryD(int l, int r) {    return ask(r) - ask(l - 1);}void Next(int x) {    int i; for (i = q[x - 1].a + 1; i <= q[x].a; i++)        addD(i);}void ins(int id) {    q[id].n = read(); q[id].m = read(); q[id].a = read();    q[id].id = min(id, 403200);}int solve(int x) {    Next(x); int i, r = min(q[x].n, q[x].m), ans = 0;    for (i = 1; i <= r;) {        int nxt = min(q[x].n / (q[x].n / i), q[x].m / (q[x].m / i));        ans += (q[x].n / i) * (q[x].m / i) * queryD(i, nxt);        i = nxt + 1;    }    return ans < 0 ? ans += 2147483648ll : ans;}int main() {    sieve(); int i; Q = read();    for (i = 1; i <= Q; i++) ins(i);    sort(q + 1, q + Q + 1, cpyz);    for (i = 1; i <= Q; i++) ans[q[i].id] = solve(i);    for (i = 1; i <= Q; i++) printf("%d\n", ans[i]);    return 0;}
阅读全文
0 0
原创粉丝点击