题目大意:
求
∑
i
=
1
n
∑
t
∣
i
t
[
g
c
d
(
t
,
i
t
)
=
1
]
\sum_{i=1}^{n}\sum_{t|i}^{}t[gcd(t,\frac it)=1]
∑i=1n∑t∣it[gcd(t,ti)=1]
n
≤
1
e
12
,
T
≤
10
n \leq 1e12,T \leq 10
n≤1e12,T≤10
题目思路:
这题在推导公式的时候有比较多的技巧需要使用.如下:
①换求和枚举顺序,消去整除符号:
= ∑ t = 1 n ∑ t ∣ i n t [ g c d ( t , i t ) = 1 ] =\sum_{t=1}^{n}\sum_{t|i}^{n}t[gcd(t,\frac it)=1] =∑t=1n∑t∣int[gcd(t,ti)=1]
= ∑ t = 1 n t ∑ i = 1 n t [ g c d ( t , i ) = 1 ] =\sum_{t=1}^{n}t\sum_{i=1}^{\frac nt}[gcd(t,i)=1] =∑t=1nt∑i=1tn[gcd(t,i)=1]
= ∑ t = 1 n t ∑ i = 1 n t ∑ d ∣ g c d ( t , i ) μ ( d ) =\sum_{t=1}^{n}t\sum_{i=1}^{\frac nt}\sum_{d|gcd(t,i)}^{}\mu(d) =∑t=1nt∑i=1tn∑d∣gcd(t,i)μ(d)
②继续换求和枚举顺序,消去整除符号:
= ∑ d = 1 n μ ( d ) ∑ t = 1 n t ∑ i = 1 n t [ d ∣ g c d ( t , i ) ] =\sum_{d=1}^{n}\mu(d)\sum_{t=1}^{n}t\sum_{i=1}^{\frac nt}[d|gcd(t,i)] =∑d=1nμ(d)∑t=1nt∑i=1tn[d∣gcd(t,i)]
③ ∵ d ∣ g c d ( t , i ) ↔ d ∣ t ⋀ d ∣ i , 同 时 这 里 也 要 注 意 上 下 限 的 变 换 \because d|gcd(t,i) \leftrightarrow d|t\bigwedge d|i,同时这里也要注意上下限的变换 ∵d∣gcd(t,i)↔d∣t⋀d∣i,同时这里也要注意上下限的变换
= ∑ d = 1 n μ ( d ) ∑ t = 1 n d t d ∑ i = 1 n t d 2 1 =\sum_{d=1}^{n}\mu(d)\sum_{t=1}^{\frac nd}td\sum_{i=1}^{\frac{n}{td^2}}1 =∑d=1nμ(d)∑t=1dntd∑i=1td2n1
= ∑ d = 1 n μ ( d ) d ∑ t = 1 n d t ∑ i = 1 n t d 2 1 =\sum_{d=1}^{n}\mu(d)d\sum_{t=1}^{\frac nd}t\sum_{i=1}^{\frac{n}{td^2}}1 =∑d=1nμ(d)d∑t=1dnt∑i=1td2n1
④令 T = t d 2 T=td^2 T=td2
= ∑ T = 1 n ∑ d = 1 n μ ( d ) d ∑ t = 1 n d t ∑ i = 1 n t d 2 [ T = t d 2 ] =\sum_{T=1}^{n}\sum_{d=1}^{n}\mu(d)d\sum_{t=1}^{\frac nd}t\sum_{i=1}^{\frac{n}{td^2}}[T=td^2] =∑T=1n∑d=1nμ(d)d∑t=1dnt∑i=1td2n[T=td2]
⑤ ∑ i = 1 n t d 2 \sum_{i=1}^{\frac{n}{td^2}} ∑i=1td2n和 [ T = t d 2 ] [T=td^2] [T=td2]无关,转化成乘法:
= ∑ T = 1 n ⌊ n T ⌋ ∑ d = 1 n μ ( d ) d ∑ t = 1 n d t [ T = t d 2 ] =\sum_{T=1}^{n}\lfloor\frac{n}{T}\rfloor\sum_{d=1}^{n}\mu(d)d\sum_{t=1}^{\frac nd}t[T=td^2] =∑T=1n⌊Tn⌋∑d=1nμ(d)d∑t=1dnt[T=td2]
⑥观察到 [ T = t d 2 ] [T=td^2] [T=td2],考虑枚举 d 2 d^2 d2的倍数
= ∑ T = 1 n ⌊ n T ⌋ ∑ d 2 ∣ T n μ ( d ) d ∑ t = 1 n d t [ T = t d 2 ] =\sum_{T=1}^{n}\lfloor\frac{n}{T}\rfloor\sum_{d^2|T}^{n}\mu(d)d\sum_{t=1}^{\frac nd}t[T=td^2] =∑T=1n⌊Tn⌋∑d2∣Tnμ(d)d∑t=1dnt[T=td2]
⑦在已知 T T T和 d 2 d^2 d2的情况下, ∑ t = 1 n d t [ T = t d 2 ] \sum_{t=1}^{\frac nd}t[T=td^2] ∑t=1dnt[T=td2]部分可转化为:
= ∑ T = 1 n ⌊ n T ⌋ ∑ d 2 ∣ T n μ ( d ) d ∑ t = 1 n d t [ t = T d 2 ] =\sum_{T=1}^{n}\lfloor\frac{n}{T}\rfloor\sum_{d^2|T}^{n}\mu(d)d\sum_{t=1}^{\frac nd}t[t=\frac{T}{d^2}] =∑T=1n⌊Tn⌋∑d2∣Tnμ(d)d∑t=1dnt[t=d2T]
⑧观察: ∑ t = 1 n d t [ t = T d 2 ] \sum_{t=1}^{\frac nd}t[t=\frac{T}{d^2}] ∑t=1dnt[t=d2T]
t ∈ [ 1 , n d ] , t\in[1,\frac nd], t∈[1,dn],而 n d ≥ T d ≥ T d 2 \frac nd\geq \frac{T}{d}\geq\frac T{d^2} dn≥dT≥d2T
⑨所以 [ t = T d 2 ] [t=\frac{T}{d^2}] [t=d2T]在 t ∈ [ 1 , n d ] t\in[1, \frac nd] t∈[1,dn]中必然成立且恰好只成立一次。
= ∑ T = 1 n ⌊ n T ⌋ ∑ d 2 ∣ T n μ ( d ) T d =\sum_{T=1}^{n}\lfloor\frac{n}{T}\rfloor\sum_{d^2|T}^{n}\mu(d)\frac{T}{d} =∑T=1n⌊Tn⌋∑d2∣Tnμ(d)dT
⑩变换枚举顺序,消除整除符号:
= ∑ d = 1 n μ ( d ) ∑ T = 1 n ⌊ n T ⌋ [ d 2 ∣ T ] T d =\sum_{d=1}^{\sqrt n}\mu(d)\sum_{T=1}^{n}\lfloor\frac{n}{T}\rfloor[d^2|T]\frac{T}{d} =∑d=1nμ(d)∑T=1n⌊Tn⌋[d2∣T]dT
(十一)从枚举 T T T改成枚举 k = T d 2 k=\frac T{d^2} k=d2T
= ∑ d = 1 n μ ( d ) ∑ k = 1 ⌊ n d 2 ⌋ ⌊ n k d 2 ⌋ k d 2 d =\sum_{d=1}^{\sqrt n}\mu(d)\sum_{k=1}^{\lfloor\frac n{d^2}\rfloor}\lfloor\frac{n}{kd^2}\rfloor\frac{kd^2}{d} =∑d=1nμ(d)∑k=1⌊d2n⌋⌊kd2n⌋dkd2
= ∑ d = 1 n μ ( d ) d ∑ k = 1 ⌊ n d 2 ⌋ ⌊ ⌊ n d 2 ⌋ k ⌋ k =\sum_{d=1}^{\sqrt n}\mu(d)d\sum_{k=1}^{\lfloor\frac n{d^2}\rfloor}\lfloor\frac{\lfloor \frac n{d^2}\rfloor}{k}\rfloor k =∑d=1nμ(d)d∑k=1⌊d2n⌋⌊k⌊d2n⌋⌋k
(十二)令 F ( n ) = ∑ i = 1 n i ∗ ⌊ n i ⌋ F(n)=\sum_{i=1}^{n}i * \lfloor \frac {n}{i} \rfloor F(n)=∑i=1ni∗⌊in⌋
原 式 = ∑ d = 1 n μ ( d ) ∗ d ∗ F ( ⌊ n d 2 ⌋ ) 原式=\sum_{d=1}^{\sqrt n}\mu(d)*d*F(\lfloor \frac n{d^2}\rfloor) 原式=∑d=1nμ(d)∗d∗F(⌊d2n⌋)
复杂度分析:
外层直接枚举 n \sqrt n n次, F ( i ) F(i) F(i)复杂度为: i \sqrt i i
所以复杂度可以写成以下和式:
∑
i
=
1
n
n
i
2
=
∑
i
=
1
n
n
i
=
n
l
o
g
n
\sum_{i=1}^{\sqrt n}\sqrt{\frac {n}{i^2}}=\sum_{i=1}^{\sqrt n}\frac{\sqrt{n}}{i}=\sqrt n log{\sqrt n}
∑i=1ni2n=∑i=1nin=nlogn
细节补充:
形如: ∑ d = 1 n g ( d ) ∗ f ( ⌊ n d 2 ⌋ ) \sum_{d=1}^{n}g(d)*f(\lfloor \frac n{d^2}\rfloor) ∑d=1ng(d)∗f(⌊d2n⌋)的式子如何整除分块?
直接套用整除分块的定义: r 2 = ⌊ n ⌊ n l 2 ⌋ ⌋ r^2=\lfloor \frac{n}{\lfloor \frac{n}{l^2} \rfloor}\rfloor r2=⌊⌊l2n⌋n⌋
r = ⌊ n ⌊ n l 2 ⌋ ⌋ r=\sqrt{\lfloor \frac{n}{\lfloor \frac{n}{l^2} \rfloor}\rfloor} r=⌊⌊l2n⌋n⌋
进一步优化
由于这题的常数很大,可能会 T T T。尝试从以下几个方面来考虑优化:
一.利用细节补充我们可以将外层的循环转化成一个数论分块。那么问题就变成了数论分块套数论分块。
二. F F F函数输出只和输入有关,可以记忆化一下.
三.考虑预处理 F F F函数:
推导:
F
(
n
)
=
∑
i
=
1
n
i
∗
⌊
n
i
⌋
=
∑
i
=
1
n
i
∗
∑
i
∣
j
n
1
=
∑
j
=
1
n
∑
i
∣
j
i
=
∑
j
=
1
n
σ
(
j
)
F(n)=\sum_{i=1}^{n}i * \lfloor \frac {n}{i} \rfloor=\sum_{i=1}^{n}i * \sum_{i|j}^{n}1=\sum_{j=1}^{n}\sum_{i|j}^{}i=\sum_{j=1}^{n}\sigma(j)
F(n)=∑i=1ni∗⌊in⌋=∑i=1ni∗∑i∣jn1=∑j=1n∑i∣ji=∑j=1nσ(j)
所以 F ( n ) F(n) F(n)为约数和的 n n n项前缀和.可以上筛法
AC代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pii pair<int,int>
#define pb push_back
#define mp make_pair
#define vi vector<int>
#define vll vector<ll>
#define fi first
#define se second
const int maxn = 1e6 + 5;
const int mod = 1e9 + 7;
int u[maxn] , bk[maxn] , p[maxn] , cnt;
ll sum[maxn];
ll g[maxn];
void init ()
{
u[1] = 1;
for (int i = 2 ; i < maxn ; i++){
if (!bk[i]){
p[++cnt] = i;
u[i] = -1;
}
for (int j = 1 ; j <= cnt && i * p[j] < maxn ; j++){
bk[i * p[j]] = 1;
if (i % p[j] == 0) {
u[i * p[j]] = 0;
break;
}else {
u[i * p[j]] = -u[i];
}
}
}
for (int i = 1 ; i < maxn ; i++){
for (int j = i ; j < maxn ; j += i){
g[j] = (g[j] + i) % mod;
}
}
for (int i = 1 ; i < maxn ; i++){
sum[i] = (sum[i - 1] + 1ll * (u[i] + mod) % mod * i % mod) % mod;
g[i] = (g[i - 1] + g[i]) % mod;
}
return ;
}
ll ksm (ll a , ll b){ ll ans = 1 , base = a;
while (b){if (b & 1) ans = ans * base % mod;b >>= 1;base = base * base % mod;}return ans;}
ll inv2 = ksm(2 , mod - 2);
unordered_map<ll , ll> dp;
ll F (ll n){
//if (n < maxn) return g[n];
if ( dp.count(n) ) return dp[n];
ll ans = 0;
ll x , y , z;
for (ll l = 1 , r; l <= n ; l = r + 1){
r = n / (n / l);
x = (r - l + 1) % mod;
y = (l + r) % mod;
z = (n / l) % mod;
ll a = x * y % mod;
a = a * inv2 % mod;
a = a * z % mod;
ans = (ans + a) %mod;
}
return dp[n] = ans;
}
int main()
{
ios::sync_with_stdio(false);
init();
int t; cin >> t;
dp.clear();
while (t--){
ll n; cin >> n;
ll ans = 0;
ll m = sqrt(n);
ll x;
for (ll l = 1 , r; l <= m ; l = r + 1){
x = n / l / l;
r = min((ll)sqrt(n / x) , m);
ll res = (sum[r] - sum[l - 1] + mod) %mod;
res = res * F(x) % mod;
ans = (ans + res) % mod;
}
cout << ans << endl;
}
return 0;
}