bzoj [SDOI2014]数表 莫比乌斯反演 BIT

bzoj [SDOI2014]数表 莫比乌斯反演 BIT

链接

bzoj
luogu
loj

思路

\[
\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{m}a*[f[gcd(i,j)]<=a]
\]

\[
f[]可以O(n)预处理出来
\]

\[
\sum\limits_{k=1}^{n}f[k]*\sum\limits_{i=1}^{m}\sum\limits_{j=1}^{m}[gcd(i,j)==k]
\]

\[
\sum\limits_{k=1}^{n}f[k]*\sum\limits_{i=1}^{\frac{n}{k}}{\frac{n}{ki}}{\frac{m}{ki}}\mu(i)
\]

\[
\sum\limits_{i=1}^{n}f[i]*\sum\limits_{k|d}{\frac{n}{d}\frac{m}{d}}\mu(\frac{d}{i})
\]

d替换k*i
\[
\sum\limits_{d=1}^{n} \frac{n}{d} \frac{m}{d} \sum\limits_{k|d} \mu(\frac{d}{k})f(k)
\]
\[
\sum\limits_{d=1}^{n} \frac{n}{d} \frac{m}{d} g(d)
\]

\[
g(d)=\sum\limits_{k|d} \mu(\frac{d}{k})f(k)
\]

询问按照a排序,每次加入f(k)时候影响的只是能k|d的g(d)
每次修改就是\(O(\sqrt{n}logn)\)
查询也是一样,
总的就是\(O(T\sqrt{n}logn)\)
注意,ll+取模的话,loj会超时,用int的自然溢出就快了三倍(300ms),是int,不是unsigned int。

其他

线性筛约数和

\[
x=p_{1}^{w_1}p_{2}^{w_2}…p_{k}^{w_k}
\]

那么

\[
SD(x)=约数和=(1+p_1^1+p_1^2+…+p_1^{w_1})(1+p_2^1+p_2^2+…+p_2^{w_2})(1+p_k^1+p_k^2+…+p_k^{w_k})
\]

0x00 是个素数

显然\(SD(pri)=pri+1\)

0x01 两两互质

是个积性函数
因为x,y两两互质,所以他们质因子互不相交,所以显然脑补公式

\[
SD(x*y)=SD(x)*SD(y)(gcd(x,y)==1)
\]

0x02 两两不互质(i%pri[j]!=0)

再开个数组tmp,记录最小质因子因子的贡献\((1+p_1^1+p_1^2+…+p_1^{w_1})\)
因为pri[j]是他的最小质因子(因为这是线性筛)
我们之前求出的i的

\[
SD(i)=(1+p_1^1+p_1^2+…+p_1^{w_1})(1+p_2^1+p_2^2+…+p_2^{w_2})(1+p_k^1+p_k^2+…+p_k^{w_k})
\]

现在的\(i*pri[j]\)的SD显然就是

\[
SD(i*pri[j])=(1+p_1^1+p_1^2+…+p_1^{w_1}+p_1^{w_1+1})(1+p_2^1+p_2^2+…+p_2^{w_2})(1+p_k^1+p_k^2+…+p_k^{w_k})
\]

改变的只有最小因子的贡献,tmp的作用就来了
tmp[i]我们已经求出来了,那么
\[tmp[i*pri[j]]=tmp[i]*pri[j]+1(这是个等差数列)\]

\[
SD[i*pri[j]]=SD[i]/tmp[i]*tmp[i*pri[j]]
\]

代码

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 6;
int read() {
    int x = 0, f = 1; char s = getchar();
    for (; s > '9' || s < '0'; s = getchar()) if (s == '-') f = -1;
    for (; s >= '0' && s <= '9'; s = getchar()) x = x * 10 + s - '0';
    return x * f;
}
int pri[N], tot, vis[N], mu[N];
int f[N], tmp[N];
struct node {
    int n, m, a, id;
    int ans;
    bool operator < (const node &b) const {
        return a < b.a;
    }
} Q[N];
bool cmp(node a, node b) {
    return a.id < b.id;
}
pair<int,int> F[N];
void Euler(int limit) {
    f[1] = tmp[1] = mu[1] = 1;
    for (int i = 2; i <= limit; ++i) {
        if (!vis[i]) {
            mu[i] = -1;
            pri[++tot] = i;
            f[i] = i + 1;
            tmp[i] = i + 1;
        }
        for (int j = 1; j <= tot && i * pri[j] <= limit; ++j) {
            vis[i * pri[j]] = 1;
            if (i % pri[j] == 0) {
                tmp[i * pri[j]] = tmp[i] * pri[j] + 1;
                f[i * pri[j]] =  f[i] / tmp[i] * tmp[i * pri[j]];
                mu[i * pri[j]] = 0;
                break;
            }
            mu[i * pri[j]] = -mu[i];
            f[i * pri[j]] = f[i] * f[pri[j]];
            tmp[i * pri[j]] = pri[j] + 1;
        }
    }
    for (int i = 1; i <= limit; ++i) {
        F[i].first = f[i], F[i].second = i;
    }
    sort(F + 1, F + 1 + limit);
}
namespace BIT {
    int sum[N];
    int lowbit(int x) {return x & (-x);}
    void add(int x, int ad) {
        for (int i = x; i <= 100000; i += lowbit(i)) sum[i] = (sum[i] + ad);
    }
    int query(int x) {
        int ans = 0;
        for (int i = x; i >= 1; i -= lowbit(i)) ans = (ans + sum[i]);
        return ans;
    }
}
int main() {
    Euler(100000);
    int T = read();
    for (int i = 1; i <= T; ++i) {
        Q[i].n = read(),Q[i].m = read(),Q[i].a = read(), Q[i].id = i;
    }
    sort(Q + 1, Q + 1 + T);
    int now = 0;
    for (int i = 1; i <= T; ++i) {
        while (now + 1 <= 100000 && Q[i].a >= F[now + 1].first) {
            now++;
            for (int j = F[now].second; j <= 100000; j += F[now].second) {
                BIT::add(j, mu[j / F[now].second] * F[now].first);
            }
        }
        int ans = 0;
        if (Q[i].n > Q[i].m) swap(Q[i].n, Q[i].m);
        for (int l = 1, r; l <= Q[i].n; l = r + 1) {
            r = min(Q[i].n / (Q[i].n / l), Q[i].m / (Q[i].m / l));
            ans += 1LL * (Q[i].n / l) * (Q[i].m / l) * (BIT::query(r) - BIT::query(l - 1));
        }
        Q[i].ans = ans;
    }
    sort(Q + 1, Q + 1 + T, cmp);
    for (int i = 1; i <= T; ++i) printf("%u\n", Q[i].ans < 0 ? Q[i].ans + 2147483648 : Q[i].ans);
    return 0;
}

原文地址:https://www.cnblogs.com/dsrdsr/p/10807765.html

时间: 2024-10-14 00:45:58

bzoj [SDOI2014]数表 莫比乌斯反演 BIT的相关文章

BZOJ 3529: [Sdoi2014]数表 [莫比乌斯反演 树状数组]

3529: [Sdoi2014]数表 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 1399  Solved: 694[Submit][Status][Discuss] Description 有一张N×m的数表,其第i行第j列(1 < =i < =礼,1 < =j < =m)的数值为能同时整除i和j的所有自然数之和.给定a,计算数表中不大于a的数之和. Input 输入包含多组数据.    输入的第一行一个整数Q表示测试点内的数据

bzoj 3529 [Sdoi2014]数表 (莫比乌斯反演+树状数组+离线)

题目大意:有一张$n*m$的数表,第$i$行第$j$列的数是同时能整除$i,j$的所有数之和,求数表内所有不大于A的数之和 先是看错题了...接着看对题了发现不会做了...刚了大半个下午无果 看了Po姐的题解(Orzzz)才搞懂这道题,搞清楚了莫比乌斯反演的两种经典的卷积形式的不同之处 令$\sigma(i)$表示i的约数个数和 如果去掉A这个限制,则题目是让我们求$\sum_{i=1}^{n}\sum_{j=1}^{m}\sigma(gcd(i,j))$ 考虑如何正确转化式子,让我们能够把不大

【BZOJ3529】[Sdoi2014]数表 莫比乌斯反演+树状数组

[BZOJ3529][Sdoi2014]数表 Description 有一张N×m的数表,其第i行第j列(1 < =i < =礼,1 < =j < =m)的数值为能同时整除i和j的所有自然数之和.给定a,计算数表中不大于a的数之和. Input 输入包含多组数据.    输入的第一行一个整数Q表示测试点内的数据组数,接下来Q行,每行三个整数n,m,a(|a| < =10^9)描述一组数据. Output 对每组数据,输出一行一个整数,表示答案模2^31的值. Sample I

BZOJ 3529([Sdoi2014]数表-莫比乌斯反演)

有一张N×m的数表,其第i行第j列(1 < =i < =n,1 < =j < =m)的数值为能同时整除i和j的所有自然数之和.给定a,计算数表中不大于a的数之和模2^31的值模2^31的值. 1<=n.m<=10 5 ,Q<=2×10 4  组询问 记k的约数和f(k) 求∑ n i=1 ∑ m j=1 gcd(i,j)[f(gcd(i,j))≤a] #include<bits/stdc++.h> using namespace std; #defin

bzoj 3529 数表 莫比乌斯反演+树状数组

题目大意: 有一张N×m的数表,其第i行第j列(1 < =i < =礼,1 < =j < =m)的数值为能同时整除i和j的所有自然数之和.给定a,计算数表中不大于a的数之和. http://wenku.baidu.com/link?url=1zHluup-GXHdByoQXhMRwRu22Uu15y4DztIr1_hKVxjHJmuLQF4_01UQhLEOR7RJIpsGyfD_5fXrx9DE7sY6JeukaNUY83In097GjUOmZ7K ppt课件中讲的很仔细了 1

BZOJ 3529 数表(莫比乌斯反演)

http://www.lydsy.com/JudgeOnline/problem.php?id=3529 思路:令F(i)为i的约数和, 1<=x<=n,1<=y<=m G(i)为i|gcd(x,y)的个数 g(i)为i=gcd(x,y)的个数 G(i)=floor(n/i)*floor(m/i) g(i)=Σu(d/i)*G(d) (i|d) F(i)可以用线性筛O(n)处理 ans=(1<=i<=min(n,m)) Σg(i)*F(i)=Σ F(i)*ΣG(d)*u

[SDOI2014]数表 莫比乌斯反演

---题面--- 题解: 设$f(d)$表示数$d$的约数和,那么$(i, j)$中的数为$f(gcd(i, j))$,那么有2种枚举方法.1,枚举每一格看对应的$f(d)$是几.$$ans = \sum_{i = 1}^{n}\sum_{j = 1}^{m}{f(gcd(i, j))}$$2,枚举$d$看有哪些格子的$f$值为$f(d)$.$$ans = \sum_{i = 1}^{min(n, m)}{f(d)}\sum_{x = 1}^{n}\sum_{y = 1}^{m}[gcd(x,

bzoj 2440 简单莫比乌斯反演

题目大意: 找第k个非平方数,平方数定义为一个数存在一个因子可以用某个数的平方来表示 这里首先需要考虑到二分才可以接下来做 二分去查找[1 , x]区间内非平方数的个数,后面就是简单的莫比乌斯反演了 容斥原理的思想,首先考虑所有数都属于非平方数 那么就是x 然后对于每一个平方数都要减去,但是这里应该只考虑质数的平方数就可以了 那么就扩展为x - x/(2^2) - x/(3^2) - x/(k^2).... 然后因为中间存在重复减的那么要加回来 -> x - x/(2^2) - x/(3^3) 

BZOJ 2818 Gcd (莫比乌斯反演 或 欧拉函数)

2818: Gcd Time Limit: 10 Sec  Memory Limit: 256 MB Submit: 2534  Solved: 1129 [Submit][Status][Discuss] Description 给定整数N,求1<=x,y<=N且Gcd(x,y)为素数的 数对(x,y)有多少对. Input 一个整数N Output 如题 Sample Input 4 Sample Output 4 HINT hint 对于样例(2,2),(2,4),(3,3),(4,2)