题目链接:ACM-ICPC 2018 南京赛区网络预赛 J-Sum
题意
\;\;\;\;
f
[
i
]
f[i]
f[i] 表示有序整数对
(
a
,
b
)
(a,b)
(a,b),满足
a
b
=
i
ab=i
ab=i 的数量。
\;\;\;\;\;\;
eg:
f
[
6
]
=
4
f[6] = 4
f[6]=4,
6
=
1
⋅
6
=
6
⋅
1
=
2
⋅
3
=
3
⋅
2
6 = 1 \cdot 6 = 6 \cdot 1 = 2 \cdot 3 = 3 \cdot 2
6=1⋅6=6⋅1=2⋅3=3⋅2.
\;\;\;\; 求 f f f 的前 n n n 项和。
\;\;\;\; 1 ≤ T ≤ 20 , 1 ≤ n ≤ 2 ∗ 1 0 7 1 \leq T \leq 20, 1 \leq n \leq 2*10^{7} 1≤T≤20,1≤n≤2∗107.
思路一(欧拉筛)
\;\;\;\;
欧拉筛的思路:每个数被其最小素因子标记。
\;\;\;\;
将一个数质因子分解:
n
=
p
1
e
1
⋅
p
2
e
2
⋅
p
3
e
3
.
.
.
n = p_{1}^{e_{1}} \cdot p_{2}^{e_{2}} \cdot p_{3}^{e_{3}}...
n=p1e1⋅p2e2⋅p3e3... ,在其所有的指数
e
1
,
e
2
,
e
3
.
.
.
e_{1},e_{2}, e_{3}...
e1,e2,e3... 中:
\;\;\;\;\;\;
若
e
i
=
1
e_{i} =1
ei=1,那么
p
i
p_{i}
pi 可以放在
a
a
a 或
b
b
b 中,对
f
[
n
]
f[n]
f[n] 贡献为
×
2
\times2
×2;
\;\;\;\;\;\;
若
e
i
=
2
e_{i} =2
ei=2,那么
p
i
p_{i}
pi 必须拆开,一个放在
a
a
a 中,另一个放在
b
b
b 中,对
f
[
n
]
f[n]
f[n] 贡献为
×
1
\times1
×1;
\;\;\;\;\;\;
若
e
i
>
2
e_{i} >2
ei>2,那么
p
i
p_{i}
pi 无论怎么拆分,在
a
a
a 或
b
b
b 中总会有平方数或其倍数,这时
f
[
n
]
=
0
f[n] = 0
f[n]=0.
代码一
/*
nero
https://nanti.jisuanke.com/t/A1956
c[i]记录最小质因子的指数
*/
#include <map>
#include <cmath>
#include <queue>
#include <cstdio>
#include <string>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <bits/stdc++.h>
using namespace std;
#define lson(u) (u<<1)
#define rson(u) (u<<1|1)
#define Pi acos(-1)
#define iINF 0x3f3f3f3f
#define lINF 0x3f3f3f3f3f3f3f
#define EPS 0.000000001
#define pii pair<int,int>
typedef long long ll;
typedef unsigned long long ull;
const int MAXN = 20000005;
const ll Mod = 1000000007;
#define MOD(a, b) a>=b?a%b+b:a
int prime[MAXN], c[MAXN];
ll f[MAXN];
bool Isprime[MAXN];
void Init(){
int N = MAXN-5, cnt = 0;
f[1] = 1;
for(int i = 2; i <= N; i++){
if(!Isprime[i]) {
prime[++cnt] = i;
f[i] = 2;
c[i] = 1;
}
for(int j = 1; j <= cnt && (ll)i*prime[j] <= N; j++) {
int x = i*prime[j];
Isprime[x] = 1;
if(i%prime[j] == 0) {
c[x] = c[i] + 1;
if(c[x] == 2) { // 指数为 2
f[x] = f[i/prime[j]];
}
else { // 指数 > 3
f[x] = 0;
}
break;
}
else { // 指数为 1
c[x] = 1; // WA c[x] = c[i]
f[x] = f[i] * 2;
}
}
}
for(int i = 1; i <= N; i++) {
f[i] += f[i-1];
}
}
int main() {
Init();
int T, n;
scanf("%d", &T);
while(T--) {
scanf("%d", &n);
printf("%lld\n", f[n]);
}
return 0;
}
/*
*/
思路二(数论)
\;\;\;\;
要求
∑
i
=
1
n
a
b
=
i
\sum_{i=1}^{n}ab=i
∑i=1nab=i,即求
∑
a
b
≤
n
\sum ab \leq n
∑ab≤n. 比如:当
n
=
30
,
a
=
3
n=30, a=3
n=30,a=3 时,
30
/
3
=
10
30/3=10
30/3=10,即有
10
10
10 个
b
(
1
−
10
)
b(1-10)
b(1−10) 满足条件,再删掉其中的平方数以及它们的倍数即可。
\;\;\;\;
s
u
m
[
i
]
sum[i]
sum[i] 表示前
i
i
i 数中有多少个数不含平方数因子,
p
[
i
]
p[i]
p[i] 表示第
i
i
i 个不含平方数因子的数, 则
a
n
s
=
∑
s
u
m
[
n
/
p
i
]
ans = \sum sum[n/p_{i}]
ans=∑sum[n/pi].
代码二
/*
nero
https://nanti.jisuanke.com/t/A1956
bo[j]=0 表示数 j 不含平方数因子
sum[i] 表示前i个数里面有多少个数不含平方数因子
p[i] 表示第i个不含平方数因子的数
*/
#include <map>
#include <cmath>
#include <queue>
#include <cstdio>
#include <string>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <bits/stdc++.h>
using namespace std;
#define lson(u) (u<<1)
#define rson(u) (u<<1|1)
#define Pi acos(-1)
#define iINF 0x3f3f3f3f
#define lINF 0x3f3f3f3f3f3f3f
#define EPS 0.000000001
#define pii pair<int,int>
#define MOD(a, b) a>=b?a%b+b:a
typedef long long ll;
typedef unsigned long long ull;
const int MAXN = 20000005;
const ll Mod = 1000000007;
int sum[MAXN], p[MAXN], cnt;
bool bo[MAXN];
void Init(){
int N = MAXN-5;
for(int i = 2; i <= N; i++){
ll x = i*i;
if(x > N) break;
for(int j = x; j <= N; j+=x) {
bo[j] = 1;
}
}
for(int i = 1; i <= N; i++) {
if(bo[i]) {
sum[i] = sum[i-1];
}
else {
p[++cnt] = i;
sum[i] = sum[i-1] + 1;
}
}
}
int main() {
Init();
int T, n, ans;
scanf("%d", &T);
while(T--) {
scanf("%d", &n);
ans = 0;
for(int i = 1; i <= cnt && p[i] <= n; i++) {
int idx = n/p[i];
ans += sum[idx];
}
printf("%lld\n", ans);
}
return 0;
}
/*
*/
参考:
ACM-ICPC 2018 南京赛区网络预赛 Sum(线性筛)
ACM-ICPC 2018 南京赛区网络预赛 J.sum
好久没有写博客,忽然发现有了不同语言的代码片,好评!