传送门啦
非常神奇的分块大法。
这个题一看数据范围,觉得不小,但是如果我们以 $ sqrt(x) $ 为界限,数据范围就降到了 $ x < 400 $
我们设数组 $ f[i][j] $ 表示在 % $ i $ 意义下余数是 $ j $ 的数的总和。
然后我们以 $ sqrt(n) $ 为界限,小于 $ sqrt(n) $ 的直接调用数组,剩下的暴力查找。修改的话看代码吧,真的不难。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int maxn = 150005;
inline int read(){
char ch = getchar();
int f = 1 ,x = 0;
while(ch > '9' || ch < '0'){if(ch == '-')f = -1; ch = getchar();}
while(ch >= '0' && ch <= '9'){x = (x << 1) + (x << 3) + ch - '0';ch = getchar();}
return x * f;
}
int n,m,a[maxn],x,y;
char flag;
long long f[390][390];//表示在 %i 意义下 余数是 j 的数的总和
int main(){
n = read(); m = read();
for(int i=1;i<=n;i++){
a[i] = read();
for(int j=1;j<=sqrt(n);j++)
f[j][i % j] += a[i];
}
while(m--){
cin >> flag;
x = read(); y = read();
if(flag == 'A'){
if(x * x <= n)
printf("%lld
",f[x][y]);
else {
int sum = 0;
for(int j=y;j<=n;j+=x)
sum += a[j];
printf("%d
",sum);
}
}
else {
for(int j=1;j<=sqrt(n);j++)
f[j][x % j] += y - a[x];
a[x] = y;
}
}
return 0;
}