引子
现有一公式,求
a
n
s
=
∑
i
=
1
n
⌊
n
i
⌋
ans = \sum_{i = 1} ^ {n}\lfloor{\frac{n}{i}}\rfloor
ans=∑i=1n⌊in⌋
观察发现我们可以在O(n)的时间复杂度内解决该问题
继续观察,会发现
⌊
n
i
⌋
\lfloor{\frac{n}{i}}\rfloor
⌊in⌋在一段区间内是具有相同的值
令
⌊
n
i
⌋
=
k
\lfloor{\frac{n}{i}}\rfloor = k
⌊in⌋=k 则有
⌊
n
⌊
n
i
⌋
⌋
<
=
n
⌊
n
i
⌋
=
j
\lfloor{\frac{n}{\lfloor\frac{n}{i}\rfloor}}\rfloor <= \frac{n}{\lfloor\frac{n}{i}\rfloor} = j
⌊⌊in⌋n⌋<=⌊in⌋n=j
故当前块最远位置为j, 块长为(j - i + 1)
题目分析
牛客-数论之神
对于
⌊
n
1
⌋
,
⌊
n
2
⌋
,
…
…
,
⌊
n
n
−
1
⌋
,
⌊
n
n
⌋
\lfloor{\frac{n}{1}}\rfloor, \lfloor{\frac{n}{2}}\rfloor, ……, \lfloor{\frac{n}{n - 1}}\rfloor, \lfloor{\frac{n}{n}}\rfloor
⌊1n⌋,⌊2n⌋,……,⌊n−1n⌋,⌊nn⌋
当 2 * k <= n < k * (k + 1) 共有2 * k - 1种不同的数
当 k * (k + 1) <= n < (k + 1) * (k + 1) 共有 2 * k 种不同的数
对结果升序
1, 2, ……, k, n / k, n / (k - 1), ……, n
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
int main()
{
ios::sync_with_stdio(false);
int t;
cin >> t;
while(t --)
{
ll n, p;
cin >> n >> p;//第p大
ll k = (ll)sqrt(n);
ll sum = 2 * k;//k * k <= n < k * (k + 1) 有(2 * k -1)个不同值
if(n < k * (k + 1))//k * (k + 1) <= n < (k + 1) * (k + 1) 有(2 * k)个不同值
sum --;
ll ans;
if(p <= k)//降序
{
ans = n / p;
}
else
{
ans = sum - p + 1;//有连续的1~k
}
cout << sum << " " << ans << endl;
}
}
bzoj-1968-约数研究
题目定义f(x) 为x的约数个数
先求
a
n
s
=
∑
i
=
1
n
f
(
i
)
ans = \sum_{i = 1}^{n}f(i)
ans=∑i=1nf(i)
将式子转换一下其实就是
a
n
s
=
∑
i
=
1
n
⌊
n
i
⌋
ans = \sum_{i = 1} ^ {n}\lfloor{\frac{n}{i}}\rfloor
ans=∑i=1n⌊in⌋
简单分块即可
/*
题意是1到n的约数个数之和
可以转换成1到n的(n / i)向下取整
一维数论分块模板题
*/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
int main()
{
ios::sync_with_stdio(false);
int n;
cin >> n;
ll ans = 0;
for(int i = 1, j = 1; i <= n; i = j + 1)
{
j = n / (n / i);//当前块能到达的最远位置
ans += 1l * (j - i + 1) * (n / i);//(n / i)为当前块的大小
}
cout << ans << endl;
}
bzoj 1257 余数之和
题目要求
a
n
s
=
∑
i
=
1
n
(
k
m
o
d
i
)
a
n
s
=
∑
i
=
1
n
(
k
−
i
∗
⌊
k
i
⌋
)
a
n
s
=
n
∗
k
−
∑
i
=
1
n
(
i
∗
⌊
k
i
⌋
)
\begin{aligned} ans = \sum_{i = 1}^{n}(k \mod i) \\ ans = \sum_{i = 1}^{n}(k - i * \lfloor{\frac{k}{i}}\rfloor)\\ ans = n * k - \sum_{i = 1}^{n}(i * \lfloor{\frac{k}{i}}\rfloor) \end{aligned}
ans=i=1∑n(kmodi)ans=i=1∑n(k−i∗⌊ik⌋)ans=n∗k−i=1∑n(i∗⌊ik⌋)
在一定区间
⌊
k
i
⌋
\lfloor{\frac{k}{i}}\rfloor
⌊ik⌋为定值,i成等差数列变化
/*
数论分块基础题1到n的floor(k / i) * i (floor为向下去整)
*/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
int main()
{
ios::sync_with_stdio(false);
int n, k;
cin >> n >> k;
ll ans = 1ll * n * k;
if(n >= k)
n = k;
for(int i = 1, j = 1; i <= n; i = j + 1)
{
j = k / (k / i);
int d = k / i;
if(j >= n)
j = n;
ans -= 1ll * (j - i + 1) * (j + i) * d / 2;//i呈等差数列
}
cout << ans << endl;
}
bzoj 2956 模积和
∑
i
=
1
n
∑
j
=
1
m
(
n
m
o
d
i
)
∗
(
m
m
o
d
j
)
\sum_{i = 1}^{n}\sum_{j = 1}^{m}(n \mod i) * (m \mod j)
∑i=1n∑j=1m(nmodi)∗(mmodj) (i != j)
原式可变:
∑
i
=
1
n
∑
j
=
1
m
(
n
m
o
d
i
)
∗
(
m
m
o
d
j
)
−
∑
i
=
1
min
(
n
,
m
)
(
n
m
o
d
i
)
∗
(
m
m
o
d
i
)
∑
i
=
1
n
(
n
m
o
d
i
)
∗
∑
j
=
1
m
(
m
m
o
d
j
)
−
∑
i
=
1
min
(
n
,
m
)
(
n
m
o
d
i
)
∗
(
m
m
o
d
i
)
\begin{aligned} \sum_{i = 1}^{n}\sum_{j = 1}^{m}(n \mod i) * (m \mod j) - \sum_{i = 1}^{\min(n, m)}(n \mod i) * (m \mod i)\\ \sum_{i = 1}^{n}(n \mod i) * \sum_{j = 1}^{m}(m \mod j) - \sum_{i = 1}^{\min(n, m)}(n \mod i) * (m \mod i) \end{aligned}
i=1∑nj=1∑m(nmodi)∗(mmodj)−i=1∑min(n,m)(nmodi)∗(mmodi)i=1∑n(nmodi)∗j=1∑m(mmodj)−i=1∑min(n,m)(nmodi)∗(mmodi)
后式可变:
∑
i
=
1
min
(
n
,
m
)
(
n
m
o
d
i
)
∗
(
m
m
o
d
i
)
∑
i
=
1
min
(
n
,
m
)
(
n
−
i
∗
⌊
n
i
⌋
)
∗
(
m
−
i
∗
⌊
m
i
⌋
)
∑
i
=
1
min
(
n
,
m
)
(
n
∗
m
−
n
∗
i
⌊
m
i
⌋
−
m
∗
i
⌊
n
i
⌋
+
i
2
⌊
n
i
⌋
⌊
m
i
⌋
)
\begin{aligned} \sum_{i = 1}^{\min(n, m)}(n \mod i) * (m \mod i)\\ \sum_{i = 1}^{\min(n, m)}(n - i * \lfloor{\frac{n}{i}}\rfloor) * (m - i * \lfloor{\frac{m}{i}}\rfloor)\\ \sum_{i = 1}^{\min(n, m)} (n * m - n * i \lfloor{\frac{m}{i}}\rfloor - m * i \lfloor{\frac{n}{i}}\rfloor + i^{2}\lfloor{\frac{n}{i}}\rfloor\lfloor{\frac{m}{i}}\rfloor) \end{aligned}
i=1∑min(n,m)(nmodi)∗(mmodi)i=1∑min(n,m)(n−i∗⌊in⌋)∗(m−i∗⌊im⌋)i=1∑min(n,m)(n∗m−n∗i⌊im⌋−m∗i⌊in⌋+i2⌊in⌋⌊im⌋)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const ll mod = 19940417;//mod不是质数
const ll inv = 3323403;//6在模mod意义下的逆元,6^(phi(mod) - 1)
ll sum(ll l, ll r) { return ((l + r) * (r - l + 1) / 2) % mod; }
ll sum_pow_two(ll n) { return n * (n + 1) % mod * (2 * n + 1) % mod * inv % mod; }//1^2 + 2^2 + …… + n^2 = n * (n + 1) * (2 * n + 1) / 6
ll cal(ll n)
{
ll ans = n * n % mod;
for(ll i = 1, j = 1; i <= n; i = j + 1)
{
j = n / (n / i);
ans = (ans - (n / i) * sum(i, j) % mod + mod) % mod;
}
return ans;
}
ll cal(ll n, ll m)
{
if(n > m)
swap(n, m);//让n为最小
ll ans = n * n % mod * m % mod;
for(ll i = 1, j = 1; i <= n; i = j + 1)
{
j = min(n / (n / i), m / (m / i));
ll t1 = (n * (m / i) % mod + m * (n / i) % mod) % mod * sum(i, j) % mod;
ll t2 = ((n / i) * (m / i) % mod * (sum_pow_two(1ll * j) - sum_pow_two(1ll * (i - 1)) + mod) % mod + mod) % mod;
ans = ((ans - t1 + t2) % mod + mod) % mod;
}
return ans;
}
int main()
{
ios::sync_with_stdio(false);
ll n, m;
cin >> n >> m;
ll ans = ((cal(n) * cal(m) % mod - cal(n, m)) % mod + mod) % mod;
cout << ans << endl;
}