[SDOI 2014]数表

Description

    有一张N×m的数表,其第i行第j列(1 < =i < =N,1 < =j < =m)的数值为
能同时整除i和j的所有自然数之和。给定a,计算数表中不大于a的数之和。

Input

    输入包含多组数据。
    输入的第一行一个整数Q表示测试点内的数据组数,接下来Q行,每行三个整数n,m,a(|a| < =10^9)描述一组数据。

Output

    对每组数据,输出一行一个整数,表示答案模2^31的值。

Sample Input

2
4 4 3
10 10 5

Sample Output

20
148

HINT

1 < =N.m < =10^5  , 1 < =Q < =2×10^4

题解

假设没有 $a$ 的限制,那么题目就是求 $$sum_{i=1}^nsum_{j=1}^msigma(gcd(i,j))$$

这个 $sigma$ 太鬼辣!我们用 $♂$ 来代替它。

我们提出 $gcd(i,j)$ egin{aligned}ans&=sum_{d=1}^{min{n,m}}♂(d)sum_{i=1}^nsum_{j=1}^m[gcd(i,j)=d]\&=sum_{d=1}^{min{n,m}}♂(d)sum_{i=1}^{leftlfloorfrac{n}{d} ight floor}sum_{j=1}^{leftlfloorfrac{m}{d} ight floor}[gcd(i,j)=1]\&=sum_{d=1}^{min{n,m}}♂(d)sum_{i=1}^{leftlfloorfrac{n}{d} ight floor}sum_{j=1}^{leftlfloorfrac{m}{d} ight floor}sum_{kmid gcd(i,j)}mu(k)\&=sum_{d=1}^{min{n,m}}♂(d)sum_{i=1}^{leftlfloorfrac{n}{d} ight floor}sum_{j=1}^{leftlfloorfrac{m}{d} ight floor}sum_{kmid gcd(i,j)}mu(k)\&=sum_{d=1}^{min{n,m}}♂(d)sum_{k=1}^{minleft{leftlfloorfrac{n}{d} ight floor,leftlfloorfrac{m}{d} ight floor ight}}mu(k)leftlfloorfrac{n}{kd} ight floorleftlfloorfrac{m}{kd} ight floorend{aligned}

令 $T=kd$ ,枚举 $T$ $$ans=sum_{T=1}^{min{n,m}}leftlfloorfrac{n}{T} ight floorleftlfloorfrac{m}{T} ight floorsum_{kmid T}♂(k)muleft(frac{T}{k} ight)$$

我们让后面那个狄利克雷卷积形式记作 $F(T)$ $$ans=sum_{T=1}^{min{n,m}}F(T)leftlfloorfrac{n}{T} ight floorleftlfloorfrac{m}{T} ight floor$$

现在就好求了,我们可以用枚举因数的方法来算出函数 $F$ 的值。

现在回到原问题,我们发现 $a$ 的约束还是不好操作。但我们想对于一个询问中的  $a$ 只有 $♂(d)leq a$ 的值才会对其有影响。我们考虑离线询问,将 $a$ 从小到大排序。将数值 $i$ 按 $♂(i)$ 的大小排序。枚举因数用树状数组维护前缀。

 1 //It is made by Awson on 2018.1.25
 2 #include <set>
 3 #include <map>
 4 #include <cmath>
 5 #include <ctime>
 6 #include <queue>
 7 #include <stack>
 8 #include <cstdio>
 9 #include <string>
10 #include <vector>
11 #include <cstdlib>
12 #include <cstring>
13 #include <iostream>
14 #include <algorithm>
15 #define LL long long
16 #define Abs(a) ((a) < 0 ? (-(a)) : (a))
17 #define Max(a, b) ((a) > (b) ? (a) : (b))
18 #define Min(a, b) ((a) < (b) ? (a) : (b))
19 #define Swap(a, b) ((a) ^= (b), (b) ^= (a), (a) ^= (b))
20 #define writeln(x) (write(x), putchar('
'))
21 #define lowbit(x) ((x)&(-(x)))
22 using namespace std;
23 const int N = 1e5;
24 void read(int &x) {
25     char ch; bool flag = 0;
26     for (ch = getchar(); !isdigit(ch) && ((flag |= (ch == '-')) || 1); ch = getchar());
27     for (x = 0; isdigit(ch); x = (x<<1)+(x<<3)+ch-48, ch = getchar());
28     x *= 1-2*flag;
29 }
30 void write(int x) {
31     if (x > 9) write(x/10);
32     putchar(x%10+48);
33 }
34 
35 int q, ans[N+5], sig[N+5], mu[N+5];
36 struct query {
37     int n, m, a, id;
38     bool operator < (const query &b) const {
39     return a < b.a;
40     }
41 }a[N+5];
42 struct sigma {
43     int a, id;
44     bool operator < (const sigma &b) const {
45     return a < b.a;
46     }
47 }b[N+5];
48 struct bittree {
49     int c[N+5];
50     void add(int x, int val) {for (; x <= N; x += lowbit(x)) c[x] += val; }
51     int query(int x) {
52     int ans = 0;
53     for (; x; x -= lowbit(x)) ans += c[x];
54     return ans;
55     }
56 }T;
57 
58 void get_pre() {
59     int isprime[N+5], prime[N+5], tot = 0, sumd[N+5], prod[N+5];
60     memset(isprime, 1, sizeof(isprime)); isprime[1] = 0, mu[1] = sig[1] = 1; b[1].id = b[1].a = 1;
61     for (int i = 2; i <= N; i++) {
62     if (isprime[i]) prime[++tot] = i, mu[i] = -1, sig[i] = 1+i, sumd[i] = 1+i, prod[i] = i;
63     for (int j = 1; j <= tot && i*prime[j] <= N; j++) {
64         isprime[i*prime[j]] = 0;
65         if (i%prime[j]) mu[i*prime[j]] = -mu[i], sig[i*prime[j]] = sig[i]*sig[prime[j]], sumd[i*prime[j]] = 1+prime[j], prod[i*prime[j]] = prime[j];
66         else {mu[i*prime[j]] = 0, prod[i*prime[j]] = prod[i]*prime[j], sumd[i*prime[j]] = sumd[i]+prod[i*prime[j]], sig[i*prime[j]] = sig[i]/sumd[i]*sumd[i*prime[j]]; break; }
67     }
68     b[i].id = i, b[i].a = sig[i];
69     }
70 }
71 int solve(int n, int m) {
72     if (n > m) Swap(n, m); int ans = 0;
73     for (int i = 1, last; i <= n; i = last+1) {
74     last = Min(n/(n/i), m/(m/i)); ans += (n/i)*(m/i)*(T.query(last)-T.query(i-1));
75     }
76     return ans;
77 }
78 void work() {
79     get_pre(); read(q);
80     for (int i = 1; i <= q; i++) read(a[i].n), read(a[i].m), read(a[i].a), a[i].id = i;
81     sort(a+1, a+1+q); sort(b+1, b+1+N);
82     for (int i = 1, last = 1; i <= q; i++) {
83     while (last < N && b[last].a <= a[i].a) {
84         for (int j = 1; j*b[last].id <= N; j++) if (mu[j]) T.add(j*b[last].id, mu[j]*b[last].a);
85         last++;
86     }
87     ans[a[i].id] = solve(a[i].n, a[i].m);
88     }
89     for (int i = 1; i <= q; i++) writeln(ans[i]&(~0u>>1));
90 }
91 int main() {
92     work();
93     return 0;
94 }
原文地址:https://www.cnblogs.com/NaVi-Awson/p/8350451.html