题解 首先思考没有修改操作,只有操作2。
∑
j
=
1
n
a
[
j
]
∗
[
g
c
d
(
i
,
j
)
=
=
1
]
\sum_{j=1}^{n}a[j]*[gcd(i,j)==1]
∑j=1na[j]∗[gcd(i,j)==1]等价于
∑
j
=
1
n
a
[
j
]
−
∑
j
=
1
n
a
[
j
]
[
g
c
d
(
i
,
j
)
≠
1
]
\sum_{j=1}^{n}a[j]-\sum_{j=1}^{n}a[j][gcd(i,j)\neq1]
∑j=1na[j]−∑j=1na[j][gcd(i,j)=1] 用ans来表示答案,首先ans为前面一部分,这很好计算,现在来研究后面的一部分,它表示就是下标与 i 不互质的a[j]的和。i 与 j 不互质则表明 i 与 j 拥有共同的质因子。对 i 进行质因数分解,记录用数组 p 所有的质因数,然后利用二进制枚举其质因子所构成的所有的 i 的约数 d ,用cnt记录每个约数 d 所包含质因子的个数, 显然,当 j 是 d 的倍数时,j 与 i 拥有共同质因子,所以它们不互质,再根据容斥原理,对于所有 j 满足是 d 的倍数时,
a
n
s
=
a
n
s
+
(
−
1
)
c
n
t
∗
a
[
j
]
ans=ans+(-1)^{cnt}*a[j]
ans=ans+(−1)cnt∗a[j]。但是不加优化的话是会 T 的。
∑
i
=
1
n
n
i
\sum_{i=1}^{n}\frac{n}{i}
∑i=1nin 是 nln(n) 级别的 定义数组sum[i], 表示下标是i的倍数的 a[j] 的和,这样可以O(nlogn)与处理出sum数组,那么就可以节省掉枚举d的倍数的时间,
a
n
s
=
a
n
s
+
(
−
1
)
c
n
t
∗
s
u
m
[
d
]
ans=ans+(-1)^{cnt}*sum[d]
ans=ans+(−1)cnt∗sum[d] 最后一个问题,如何考虑修改 a[i]=b 之后更新 sum 数组,我们可以
O
(
n
)
O(\sqrt{n})
O(n)级别找到 i 的约数 d ,修改对应的 sum[d] = sum[d] + b- a[i],最后将a[i]修改为b。至此所有问题都以解决。时间复杂度为
O
(
n
n
)
O(n\sqrt{n})
O(nn)
AC代码
#include<bits/stdc++.h>usingnamespace std;#define ll long long #define inf 0x3f3f3f3f#define mes(a, val) memset(a, val, sizeof a)#define mec(b, a) memcpy(b, a, sizeof a)constint maxn =1e5+10;int a[maxn];int sum[maxn];int p[30];int num =0;voidfac(int n){mes(p,0); num =0;for(int i =2; i * i <= n; i ++){if(n % i ==0){
p[++ num]= i;while(n % i ==0) n /= i;}}if(n >1) p[++ num]= n;}intfd(int n){return n &1?-1:1;}intmain(){mes(sum,0);int n, q;scanf("%d %d",&n,&q);for(int i =1; i <= n; i ++){scanf("%d",&a[i]);}for(int i =1; i <= n; i ++){for(int j = i; j <= n; j += i){
sum[i]+= a[j];}}while(q --){int op;scanf("%d",&op);if(op ==1){int x, d;scanf("%d %d",&x,&d);for(int i =1; i * i <= x; i ++){if(x % i ==0){
sum[i]+=(d - a[x]);if(x / i != i){
sum[x/i]+=(d - a[x]);}}}
a[x]= d;}elseif(op ==2){int x;scanf("%d",&x);fac(x);
ll ans = sum[1];int mx =(1<< num)-1;for(int i =1; i <= mx; i ++){int cnt =0;int x = i, d =1;int id =1;for(int j =1; j <= num; j ++){if(x &1){
d *= p[j];
cnt ++;}
x >>=1;}
ans +=fd(cnt)* sum[d];}printf("%lld\n", ans);}}return0;}