CF1207F Remainder Problem
题意
给定一个初始值全部为 ,长度为 的数列,要支持单点加上某个数,以及查询 的数列的对应的值的和,直到 时停止。
解法
限时 秒,考虑分块或线段树。但是分析后可得,线段树难以维护零散的点的和,而普通分块空间会爆。
那么我们还有一个方法:根号分治。这是一种类似分块的方法,他可以使得平均复杂度在 以内, 是数列长度。
考虑设 表示询问输入的是 时的答案,那么理论空间复杂度是 的,显然不行。我们注意到询问有一个特征,就是当 都很小的时候暴力会很慢,而当 很大时暴力可以接受。暴力的每次复杂度大约是 级别的,所以我们只需要记录 ,其中 ,那么询问的时候,如果块内有答案,直接 输出,不然暴力的理论最坏复杂度还是 的,单点修改就没什么难度了,只需要从 到 循环即可,也是 的。
所以总复杂度最坏是 的,最坏的点约 秒,稍微卡一下常数,可以通过。
代码:
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
using namespace std;
const int l = 708, N = 5e5 + 5;
int n;
long long ans[l + 5][l + 5], a[N];
int main()
{
scanf("%d", &n);
while (n--)
{
int opt, x, y;
scanf("%lld%lld%lld", &opt, &x, &y);
if (opt == 1ll)
{
a[x] += y;
for (int i = 1; i <= l; i++)
{
ans[i][x % i] += y;
}
}
else
{
if (x <= l) printf("%lld\n", ans[x][y]);
else
{
long long res = 0;
for (int i = y; i <= N - 5; i += x) res += a[i];
printf("%lld\n", res);
}
}
}
return 0;
}

浙公网安备 33010602011771号