HDU-4947
题目链接:https://acm.hdu.edu.cn/showproblem.php?pid=4947
队友刷数据结构发现的好题(指秃头)。
题目大意是这样的,给你一串长为 L L L的数组,有如下操作:
- 1 n d v 1 ~n~d~ v 1 n d v,指 g c d ( x , n ) = d gcd(x , n) = d gcd(x,n)=d的下标为 x x x的 a x a_x ax加上 v v v
- 2 2 2 x x x求 ∑ 1 x a i ∑_1^x a_i ∑1xai
数据范围:
1
≤
l
q
≤
5
e
4
1
≤
n
,
d
,
v
≤
2
e
5
,
1
≤
x
≤
l
1 \le l\\ q \le 5e4 \\ 1 \le n,d,v \le 2e5 , 1 \le x \le l
1≤lq≤5e41≤n,d,v≤2e5,1≤x≤l
被坑辽,
l
l
l的范围不是5e4,是2e5,第一次re辽
我们首思考一下暴力做法:对于
1
1
1操作,我们转化一下,
g
c
d
(
x
,
n
)
=
d
gcd(x , n ) = d
gcd(x,n)=d 可以转化为
g
c
d
(
x
/
d
,
n
/
d
)
=
1
gcd(x / d , n / d) = 1
gcd(x/d,n/d)=1,相当于什么呢?相当于:枚举
1
1
1到
l
l
l中与
n
/
d
n / d
n/d互质的数乘
d
d
d加上
v
v
v,这样的时间复杂度如何呢?枚举所有与
n
/
d
n / d
n/d互质的数的时间复杂度为:
O
(
n
/
d
)
O(n / d)
O(n/d)最坏情况为
O
(
n
)
O(n)
O(n),对于操作
2
2
2,我们可以用树状数组来做,那么这样我们发现,不考虑操作
2
2
2,光是修改,我们的时间都不够用。
这样不可取,那我们考虑优化。
[
g
c
d
(
x
,
n
)
=
d
]
⟺
[
g
c
d
(
x
/
d
,
n
/
d
)
=
1
]
[gcd(x , n) = d] \iff [gcd(x / d , n / d) = 1] \\
[gcd(x,n)=d]⟺[gcd(x/d,n/d)=1]
对于操作
1
1
1,相当于在
1
≤
x
≤
l
1 \le x \le l
1≤x≤l满足的加上
v
v
v,等价于:
[
g
c
d
(
x
/
d
,
n
/
d
)
=
1
]
∗
v
利
用
莫
比
乌
斯
函
数
的
性
质
去
掉
方
括
号
∑
i
∣
g
c
d
(
x
/
d
,
n
/
d
)
μ
(
i
)
∗
v
∑
i
∣
x
d
,
i
∣
n
d
μ
(
i
)
∗
v
n
/
d
已
知
,
我
们
枚
举
n
/
d
每
一
个
因
子
p
,
p
∗
d
即
为
x
.
ƒ
(
p
d
)
=
∑
p
d
∣
x
μ
(
p
)
∗
v
[gcd(x / d, n / d) = 1] * v\\ 利用莫比乌斯函数的性质去掉方括号\\ ∑_{i | gcd(x / d , n / d)} \mu(i) *v\\ ∑_{i | \frac{x}{d} , i | \frac{n}{d}}\mu(i) *v \\ n / d已知,我们枚举n / d每一个因子p,p * d即为x.\\ ƒ(pd) = ∑_{p d| x}\mu(p) *v \\
[gcd(x/d,n/d)=1]∗v利用莫比乌斯函数的性质去掉方括号i∣gcd(x/d,n/d)∑μ(i)∗vi∣dx,i∣dn∑μ(i)∗vn/d已知,我们枚举n/d每一个因子p,p∗d即为x.ƒ(pd)=pd∣x∑μ(p)∗v
我们定义,
a
i
=
∑
d
∣
i
f
(
d
)
a_i = ∑_{d|i}f(d)
ai=d∣i∑f(d)
那么
∑
i
=
1
x
a
i
=
∑
i
=
1
x
∑
j
∣
i
f
(
j
)
∑
i
=
1
x
a
i
=
∑
i
=
1
x
f
(
i
)
[
x
i
]
∑_{i = 1}^xa_i = ∑_{i = 1}^x ∑_{j | i} f(j)\\ ∑_{i = 1}^xa_i = ∑_{i = 1}^xf(i)[\frac{x}{i}]\\
i=1∑xai=i=1∑xj∣i∑f(j)i=1∑xai=i=1∑xf(i)[ix]
利用分块和树状数组就可以求出。
#include <bits/stdc++.h>
#define fi first
#define se second
#define PI acos(-1)
#define mk make_pair
#define lowbit(x) (x & (-x))
#define sz(x) (int)(x).size()
#define all(a) a.begin() , a.end()
#define rep(i, a, b) for (int i = (a); i <= (b); ++i)
#define pre(i, b, a) for (int i = (b); i >= (a); --i)
#define debug freopen("1.in", "r", stdin), freopen("1.out", "w", stdout);
using namespace std;
typedef long long LL;
typedef pair<int , int > PII;
const int INF = 0x3f3f3f3f;
const int N = 2e5 + 10;
bool st[N];
LL tr[N];
int l , q;
vector<int> fact[N];
int primes[N] , mobius[N] , cnt , f[N];
int get(int n , int a) {
return n / (n / a);
}
void add(int x , int v) {
for (int i = x;i <= l;i += lowbit(i)) tr[i] += v;
}
LL query(int x) {
LL ans = 0;
for (int i = x; i ; i -= lowbit(i)) ans += tr[i];
return ans;
}
void init(int n) {
mobius[1] = 1;
for (int i = 2;i <= n;i ++) {
if (!st[i]) primes[cnt ++ ] = i , mobius[i] = -1;
for (int j = 0;primes[j] <= n / i;j ++) {
st[primes[j] * i] = true;
if (i % primes[j] == 0) break;
mobius[i * primes[j]] -= mobius[i];
}
}
for (int i = 1;i <= n;i ++) {
for (int j = i;j <= n;j += i) {
fact[j].push_back(i);
}
}
}
int main(){
//ios::sync_with_stdio(false);
//cin.tie(0);
// debug
init(2e5);
int cas = 0;
while (~scanf("%d %d" , &l , &q)) {
if (!l && !q) break;
printf("Case #%d:\n" , ++ cas);
for (int i = 0;i <= l;i ++) tr[i] = 0;
while (q -- ) {
int op;
scanf("%d" , &op);
if (op == 1) {
int n , d , v;
scanf("%d %d %d", &n , &d , &v);;
if (n % d) continue;
int now = n / d;
int len = fact[now].size();
for (int i = 0;i < len;i ++) {
int p = fact[now][i];
// f[p * d] += mobius[p] * v;
add(p * d , mobius[p] * v);
}
}
else {
LL ans = 0;int x;
scanf("%d" , &x);
for (int left = 1 ,r;left <= x;left = r + 1) {
LL nowans = 0;
r = min(x , get(x , left));
nowans = query(r) - query(left - 1);
// cout << nowans << ' ';
ans += nowans * (x / left);
}
printf("%lld\n" , ans);
}
}
}
return 0;
}