跳到主要内容

数论分块

整数分块

i=1nni\sum_{i=1}^{n}\left\lfloor\frac{n}{i}\right\rfloor

性质1:分块的块数

<=2n<=2\left\lfloor\sqrt{n}\right\rfloor

i<=ni<=\left\lfloor{\sqrt{n}}\right\rfloor时,nl\lfloor\frac{n}{l}\rfloorn\lfloor{\sqrt{n}}\rfloor种取法

i>ni>\lfloor\sqrt{n}\rfloor时,ni<=n\lfloor\sqrt{\frac{n}{i}}\rfloor<=\lfloor\sqrt{n}\rfloor,最多也是n\sqrt{n}种取法

性质2:l所在块的右端点为

nnl\left\lfloor{\frac{n}{\left\lfloor{\frac{n}{l}}\right\rfloor}}\right\rfloor

[CQOI2007] 余数求和

题目描述

https://www.luogu.com.cn/problem/P2261

给出正整数 nnkk,请计算

G(n,k)=i=1nkmodiG(n, k) = \sum_{i = 1}^n k \bmod i

其中 kmodik\bmod i 表示 kk 除以 ii 的余数。

输入格式

输入只有一行两个整数,分别表示 nnkk

输出格式

输出一行一个整数表示答案。

样例输入 #1

10 5

样例输出 #1

29

样例 1 解释

G(10,5)=0+1+2+1+0+5+5+5+5+5=29G(10, 5)=0+1+2+1+0+5+5+5+5+5=29

数据规模与约定

  • 对于 30%30\% 的数据,保证 n,k103n , k \leq 10^3
  • 对于 60%60\% 的数据,保证 n,k106n, k \leq 10^6
  • 对于 100%100\% 的数据,保证 1n,k1091 \leq n, k \leq 10^9

代码

#include <bits/stdc++.h>

using namespace std;
#define int long long

signed main() {
#ifndef ONLINE_JUDGE
freopen("../test.in", "r", stdin);
freopen("../test.out", "w", stdout);
#endif
int n, k;
cin >> n >> k;
int res = n * k;
int r;
for (int l = 1; l <= n; l = r + 1) {
if (k / l == 0) break;
r = min(k / (k / l), n);
res -= (k / l) * (r - l + 1) * (l + r) / 2;
}
cout << res;
return 0;
}

Strange Function

https://www.luogu.com.cn/problem/CF1542C

题面翻译

f(i)f(i) 为最小的正整数数 xx 满足 xx 不是 ii 的因子。

现给出正整数 nn,请计算出 i=1nf(i)\sum_{i=1}^n f(i)109+710^9+7 的值。上述式子等价于 f(1)+f(2)++f(n)f(1)+f(2)+\cdots+f(n)

本题含多组数据。令数据组数为 tt,那么有 1t1041 \leq t \leq 10^41n10161 \leq n \leq 10^{16}

题目描述

Let f(i)f(i) denote the minimum positive integer xx such that xx is not a divisor of ii .

Compute i=1nf(i)\sum_{i=1}^n f(i) modulo 109+710^9+7 . In other words, compute f(1)+f(2)++f(n)f(1)+f(2)+\dots+f(n) modulo 109+710^9+7 .

输入格式

The first line contains a single integer tt ( 1t1041\leq t\leq 10^4 ), the number of test cases. Then tt cases follow.

The only line of each test case contains a single integer nn ( 1n10161\leq n\leq 10^{16} ).

输出格式

For each test case, output a single integer ansans , where ans=i=1nf(i)ans=\sum_{i=1}^n f(i) modulo 109+710^9+7 .

样例输入 #1

6
1
2
3
4
10
10000000000000000

样例输出 #1

2
5
7
10
26
366580019

提示

In the fourth test case n=4n=4 , so ans=f(1)+f(2)+f(3)+f(4)ans=f(1)+f(2)+f(3)+f(4) .

  • 11 is a divisor of 11 but 22 isn't, so 22 is the minimum positive integer that isn't a divisor of 11 . Thus, f(1)=2f(1)=2 .
  • 11 and 22 are divisors of 22 but 33 isn't, so 33 is the minimum positive integer that isn't a divisor of 22 . Thus, f(2)=3f(2)=3 .
  • 11 is a divisor of 33 but 22 isn't, so 22 is the minimum positive integer that isn't a divisor of 33 . Thus, f(3)=2f(3)=2 .
  • 11 and 22 are divisors of 44 but 33 isn't, so 33 is the minimum positive integer that isn't a divisor of 44 . Thus, f(4)=3f(4)=3 .

Therefore, ans=f(1)+f(2)+f(3)+f(4)=2+3+2+3=10ans=f(1)+f(2)+f(3)+f(4)=2+3+2+3=10 .

思路

因为f[i]=xf[i]=x,即xx是最小的不可以被ii整除的数,那么1,2,3...x11,2,3...x-1一定都是可以被ii整除的

因此i可以整除lcm(1,2,3...x1)i可以整除lcm(1,2,3...x-1),并且i不可以整除lcm(1,2,3....x1,x).i不可以整除lcm(1,2,3....x-1,x).

因为f[i]=xf[i]=x,这里的xx不会很大,估计不超过80,可以打表算一下x=lcm(1,2,3..)x=lcm(1,2,3..)

所以我们可以考虑使用数论分块的思想,根据xx的值,算有多少个数,满足f[i]=xf[i]=x.,假设有numnum个,那么对答案的贡献就是numxnum*x

如何算有多少个呢?等于满足条件的数-不满足条件的数

num=nlcm(1,2,3...x1)nlcm(1,2,3...x)num=\frac{n}{lcm(1,2,3...x-1)}-\frac{n}{lcm(1,2,3...x)}

t=lcm(1,2,3...x1)t=lcm(1,2,3...x-1)

num=ntnlcm(t,i)num=\frac{n}{t}-\frac{n}{lcm(t,i)}

代码

#include <bits/stdc++.h>

#define int long long
#define yes cout << "YES" << endl;
#define no cout << "NO" << endl;
#define IOS cin.tie(0), cout.tie(0), ios::sync_with_stdio(false);
#define cxk 1
#define debug(s, x) if (cxk) cout << "#debug:(" << s << ")=" << x << endl;
using namespace std;

const int mod = 1e9 + 7;

void solve() {
int n;
cin >> n;
int res = 0;
int cur = 1;
for (int i = 2;; i++) {
int t = i * (n / cur - n / lcm(cur, i));
t %= mod;
res = (res + t) % mod;
cur = lcm(cur, i);
if (cur > n) break;
}
cout << res << endl;
}

signed main() {
IOS
#ifndef ONLINE_JUDGE
freopen("../test.in", "r", stdin);
freopen("../test.out", "w", stdout);
#endif
int _ = 1;
cin >> _;
while (_--) solve();
return 0;
}