Codeforces-1207-F

Codeforces-1207-F

题目

题目链接

分析

以前从来没有做过这种问法的题目,觉得很有意思。

本来想的是可不可以把操作转化一下改到线段树上去,结果没有想到,好像也真的不行。

然后就灵光一闪发现当询问的 $x$ ,比较大的时候暴力查询也是跑的飞快,于是就开始想大数据暴力查询。

小数据可以发现直接维护一个二维数组 $sum[x][y]$ 表示答案。

然后大小的分隔本来以为就是 $sqrt(5 \cdot 10^5)$ ,但其实并不是,因为这道题目并不是传统意义上的分块

而是一种用空间换时间的方法,当 $x$ 比较大的时候我们很难去更新 $sum[x][y]$,也开不了那么大的空间。

思考一下,假如分割点是 $p$,那么对于更新操作来说,因为我们需要更新所有的 $sum[x][y]$ 以便查询小数据。

所以更新的复杂度就是:$O(p)$。

对于查询操作来说:如果查询的 $x \leq p$ ,那么我们可以直接输出答案也就是 $O(1)$。

如果查询的 $ x > p$,那么我们可以暴力查询,复杂度是:$O(\frac{5\cdot 10^5}{x})$。具体复杂度是:$\Omega(\frac{5\cdot 10^5}{p}) - O(1)$。

分析一下 $p$ 取 300~1000 都是可以的。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <bits/stdc++.h>
#define rep(i, a, b) for(int i = (a); i <= (b); ++i)
#define per(i, a, b) for(int i = (a); i >= (b); --i)
using namespace std;

typedef long long ll;
const int mod = 1e9+7;
const int MAXN = 5e5 + 7;

int a[MAXN];
int sum[1001][1001];
int main(int argc, char const *argv[])
{
int q;
scanf("%d", &q);
int op, x, y;
while(q--){
scanf("%d %d %d", &op, &x, &y);
if(op == 1){
a[x] += y;
for(int i = 1; i <= 1000; ++i){
sum[i][x%i] += y;
}
} else {
if(x <= 1000){
printf("%d\n", sum[x][y]);
} else {
int res = 0;
while(y <= 500000){
res += a[y];
y += x;
}
printf("%d\n", res);
}
}
}
return 0;
}
作者

Dicer

发布于

2019-08-29

更新于

2021-07-16

许可协议