题目链接:CF 或者 洛谷

一道经典的类型题,把这种类型的题拿出来单独说一下。

注意到问题中涉及到需要维护 \(a_{x+k\times step}\) 这样的信息,这样的信息很难用树型结构维护,比较容易用块级结构维护,我们注意到其实是每次这种步长 \(+step\) 的信息很难维护,我们考虑一类特殊的分块:如果 \(step\) 恰好为块长。

我们会惊讶地发现,从某个位置往后不断地走 \(step\) 就是说不断地恰好跨过一个块长,它的路径上的每个点的信息在块里都是同一个位置,这样一来其实我们可以为每一种块长分块的结果维护它特有的一些信息。

注意到一点,在预处理时,每一种块长如果我们都暴力的情况下,从小块长开始,比如从块长为 \(1\) 开始,显然处理的复杂度是 \(O(n)\),这样一来,其实我们能处理最多 \(\sqrt{n}\) 种块长,预处理的复杂度最多为 \(n\sqrt{n}\),如果更长的块长我们注意到,如果暴力地从 \(1\) 位置开始跳,那么最多也就跳 \(\sqrt{n}\) 次,此时每个 \(\ge \sqrt{n}\) 的块长其实是都是能直接暴力处理,这启发我们使用根号分治解决这类问题:

  1. \(块长 < \sqrt{n}\),考虑为这类所有块长分块维护统一的信息。

  2. \(块长 \ge \sqrt{n}\),考虑直接暴力。

这就是这类问题的模版框架。如果出现修改,我们对于查询的调整可能发生调整,比如有时候查询的是具体的值,那么可以考虑每种块长的贡献即可,最后会给出例题。

回到本题,我们需要对小块长维护怎样的信息,考虑到查询直接维护 \(a_i \times 当前查询中的下标\) 是困难的,注意到阿贝尔求和的方式,我们可以把它拆成若干个前缀和做差的方式:

\[
a_{s}\times 1+a_{s+d}\times 2+a_{s+2d}\times 3+a_{s+3d} \times 4....a_{s+(k-1)\times d}\times k
\]

先考虑简单情形:

如果 \(d==1\):

\[上式=a_s+2\times a_{s+1}+3\times a_{s+2}....k \times a_{s+k-1}
\]

类似于阿贝尔求和假如知道:

\[pre[x]=a_{1}+....a_s+a_{s+1}+a_{s+2}+....a_{x}
\]

那么很显然有原式子拆成如下图求和:

可以看出每一行都是一个区间和,借助前缀和,不妨设当前查询的最后一个数为 \(end\):

\[ 原式=(pre[end]-pre[s-1])+(pre[end]-pre[s-2])+.....(pre[end]-pre[end-1])
\]
\[=k\times pre[end]-(pre[s-1]+pre[s-2]....pre[end-1])
\]

很容易看出,前面其实就为一个前缀和,后面则是“前缀和数组”的区间和形式,显然维护前缀和数组的前缀和就能办到了。

现在抽象一下,如果 \(d \neq 1\),怎么解决:

事实上,我们把上式改写一下:

\[pre[d][idx]=a_{start}+a_{start+d}+a_{start+2d}+....a_{idx}
\]

其中 \(start\) 为从 \(idx\) 往前不断走 \(d\) 长度能达到的最早起点,换句话来说,就是最开始我们提到的那张图:

\(idx\) 此时可能不位于第一个块处,比如 \(idx=x_2\),那么 \(x_1\) 就是它在第一个块的相对位置,也即是 \(start\),我们维护的就是这一步所有 \(x\) 之和。

那么上面的式子显然可以改写为:

\[k\times pre[end]-(pre[s-d]+pre[s]+pre[s+d]+pre[s+2d]....pre[end-d])
\]

这里的 \(pre\) 第一维取 \(d\),省略第一维为上述形式。那么我们可以维护两个数组:

  1. \(pre[d][idx]\) 表示 \(d\) 长度的块的这些 \(x\) 的前缀和信息。

  2. \(Prepre[d][idx]\) 表示 \(d\) 长度的这些 \(pre[d][idx]\) 的前缀和信息。

其中易知道 \(Prepre[d][idx]=pre[d][start]+pre[d][start+d].....pre[d][idx]\)。

那么上述式子就可以轻易改写了:

\[=k \times pre[d][end]-(Prepre[d][end-d]-Prepre[d][s-2\times d])
\]

其实只需要注意到,前缀和作差中后一项不再是 \(-1\),改为 \(-d\) 即可。

最后的细节

注意到有类似 \(s-2\times d\) 这类下标,我们最好和 \(0\) 取个 \(max\),防止出现负数,究其原因可能这个块就是第一项了。然后注意到块比较小的时候,如果 \(k\) 比较小也可以暴力,那么我们可以对这两类情况同时走暴力分支也行。当然改写成后缀和也是可以的,不用怎么需要考虑越界问题,因为超过的部分你数组开大点直接能取值为 \(0\) 的后缀和了。记得多测情空。

带注释参考代码
#include <bits/stdc++.h>

// #pragma GCC optimize("Ofast,unroll-loops")
// #pragma GCC optimize(2) // #define isPbdsFile #ifdef isPbdsFile #include <bits/extc++.h> #else #include <ext/pb_ds/priority_queue.hpp>
#include <ext/pb_ds/hash_policy.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/trie_policy.hpp>
#include <ext/pb_ds/tag_and_trait.hpp>
#include <ext/pb_ds/hash_policy.hpp>
#include <ext/pb_ds/list_update_policy.hpp>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/exception.hpp>
#include <ext/rope> #endif using namespace std;
using namespace __gnu_cxx;
using namespace __gnu_pbds;
typedef long long ll;
typedef long double ld;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef tuple<int, int, int> tii;
typedef tuple<ll, ll, ll> tll;
typedef unsigned int ui;
typedef unsigned long long ull;
typedef __int128 i128;
#define hash1 unordered_map
#define hash2 gp_hash_table
#define hash3 cc_hash_table
#define stdHeap std::priority_queue
#define pbdsHeap __gnu_pbds::priority_queue
#define sortArr(a, n) sort(a+1,a+n+1)
#define all(v) v.begin(),v.end()
#define yes cout<<"YES"
#define no cout<<"NO"
#define Spider ios_base::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
#define MyFile freopen("..\\input.txt", "r", stdin),freopen("..\\output.txt", "w", stdout);
#define forn(i, a, b) for(int i = a; i <= b; i++)
#define forv(i, a, b) for(int i=a;i>=b;i--)
#define ls(x) (x<<1)
#define rs(x) (x<<1|1)
#define endl '\n'
//用于Miller-Rabin
[[maybe_unused]] static int Prime_Number[13] = {0, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37}; template <typename T>
int disc(T* a, int n)
{
return unique(a + 1, a + n + 1) - (a + 1);
} template <typename T>
T lowBit(T x)
{
return x & -x;
} template <typename T>
T Rand(T l, T r)
{
static mt19937 Rand(time(nullptr));
uniform_int_distribution<T> dis(l, r);
return dis(Rand);
} template <typename T1, typename T2>
T1 modt(T1 a, T2 b)
{
return (a % b + b) % b;
} template <typename T1, typename T2, typename T3>
T1 qPow(T1 a, T2 b, T3 c)
{
a %= c;
T1 ans = 1;
for (; b; b >>= 1, (a *= a) %= c)if (b & 1)(ans *= a) %= c;
return modt(ans, c);
} template <typename T>
void read(T& x)
{
x = 0;
T sign = 1;
char ch = getchar();
while (!isdigit(ch))
{
if (ch == '-')sign = -1;
ch = getchar();
}
while (isdigit(ch))
{
x = (x << 3) + (x << 1) + (ch ^ 48);
ch = getchar();
}
x *= sign;
} template <typename T, typename... U>
void read(T& x, U&... y)
{
read(x);
read(y...);
} template <typename T>
void write(T x)
{
if (typeid(x) == typeid(char))return;
if (x < 0)x = -x, putchar('-');
if (x > 9)write(x / 10);
putchar(x % 10 ^ 48);
} template <typename C, typename T, typename... U>
void write(C c, T x, U... y)
{
write(x), putchar(c);
write(c, y...);
} template <typename T11, typename T22, typename T33>
struct T3
{
T11 one;
T22 tow;
T33 three; bool operator<(const T3 other) const
{
if (one == other.one)
{
if (tow == other.tow)return three < other.three;
return tow < other.tow;
}
return one < other.one;
} T3() { one = tow = three = 0; } T3(T11 one, T22 tow, T33 three) : one(one), tow(tow), three(three)
{
}
}; template <typename T1, typename T2>
void uMax(T1& x, T2 y)
{
if (x < y)x = y;
} template <typename T1, typename T2>
void uMin(T1& x, T2 y)
{
if (x > y)x = y;
} constexpr int N = 1e5 + 10;
constexpr int Size = ceil(sqrt(N));
constexpr int CNT = (N + Size - 1) / Size + 1;
int n, q;
ll a[N];
ll pre[CNT + 1][N];
ll Prepre[CNT + 1][N]; inline void solve()
{
cin >> n >> q;
forn(i, 1, n)cin >> a[i];
int siz = sqrt(n);
forn(i, 1, siz)
{
forn(j, 1, n)
{
pre[i][j] = a[j];
if (j > i)pre[i][j] += pre[i][j - i];
Prepre[i][j] = pre[i][j];
if (j > i)Prepre[i][j] += Prepre[i][j - i];
}
}
forn(i, 1, q)
{
ll s, d, k;
cin >> s >> d >> k;
ll ans = 0;
if (k <= siz or d >= siz)forn(i, 1, k)ans += a[s + (i - 1) * d] * i;
else
{
int end = s + (k - 1) * d;
int endpre = end - d;
ans = k * pre[d][end] - (Prepre[d][endpre] - Prepre[d][max(s - 2 * d, 0ll)]);
}
cout << ans << " ";
}
forn(i, 1, siz)forn(j, 1, n)pre[i][j] = Prepre[i][j] = 0;
cout << endl;
} signed int main()
{
// MyFile
Spider
//------------------------------------------------------
// clock_t start = clock();
int test = 1;
// read(test);
cin >> test;
forn(i, 1, test)solve();
// while (cin >> n, n)solve();
// while (cin >> test)solve();
// clock_t end = clock();
// cerr << "time = " << double(end - start) / CLOCKS_PER_SEC << "s" << endl;
}
\[最终单个\ Test\ 的时间复杂度为预处理加若干次查询: O(n\sqrt{n}+q\sqrt{n})
\]

推荐经典题:P5309 [Ynoi2011] 初始化 题解

CF1921F Sum of Progression 题解的更多相关文章

  1. [LeetCode] Range Sum Query - Mutable 题解

    题目 题目 思路 一看就是单点更新和区间求和,故用线段树做. 一开始没搞清楚,题目给定的i是从0开始还是从1开始,还以为是从1开始,导致后面把下标都改掉了,还有用区间更新的代码去实现单点更新,虽然两者 ...

  2. Educational Codeforces Round 37-F.SUM and REPLACE题解

    一.题目 二.题目链接 http://codeforces.com/contest/920/problem/F 三.题意 给定$N$个范围在$[1, 1e6)$的数字和$M$个操作.操作有两种类型: ...

  3. CF102B Sum of Digits 题解

    Content 给定一个数 \(n\),每次操作可以将 \(n\) 变成 \(n\) 各位数之和.问你几次操作之后可以将 \(n\) 变为一位数. 数据范围:\(1\leqslant n\leqsla ...

  4. Codeforces 396B On Sum of Fractions 数论

    题目链接:Codeforces 396B On Sum of Fractions 题解来自:http://blog.csdn.net/keshuai19940722/article/details/2 ...

  5. Path Sum leetcode java

    题目: Given a binary tree and a sum, determine if the tree has a root-to-leaf path such that adding up ...

  6. 【CF914G】Sum the Fibonacci 快速??变换模板

    [CF914G]Sum the Fibonacci 题解:给你一个长度为n的数组s.定义五元组(a,b,c,d,e)是合法的当且仅当: 1. $1\le a,b,c,d,e\le n$2. $(s_a ...

  7. [Leetcode Week16]Range Sum Query - Mutable

    Range Sum Query - Mutable 题解 原创文章,拒绝转载 题目来源:https://leetcode.com/problems/range-sum-query-mutable/de ...

  8. 【leetcode刷题笔记】Path Sum

    Given a binary tree and a sum, determine if the tree has a root-to-leaf path such that adding up all ...

  9. CodeForces 85D Sum of Medians Splay | 线段树

    Sum of Medians 题解: 对于这个题目,先想到是建立5棵Splay,然后每次更新把后面一段区间的树切下来,然后再转圈圈把切下来的树和别的树合并. 但是感觉写起来太麻烦就放弃了. 建立5棵线 ...

  10. Bestcoder Round #84

    A题 Aaronson http://bestcoder.hdu.edu.cn/contests/contest_chineseproblem.php?cid=718&pid=1001 感觉一 ...

随机推荐

  1. 蓝桥杯历年省赛试题汇总 C/C++ B组

    B组 省赛 部分 A组的题目可以在这里查看 → 刷题笔记: 蓝桥杯 题目提交网站:Here 2012 第三届 微生物增殖 古堡算式 海盗比酒量 奇怪的比赛 方阵旋转 大数乘法 放旗子 密码发生器 夺冠 ...

  2. 智慧城市大数据运营中心 IOC 之 Web GIS 地图应用

    前言 IOC(Intelligent Operations Center)--智慧城市智能运营中心就是智慧城市的大脑,是建立在各个智慧应用系统之上的系统.通过对政府各职能部门的业务信息共享与整合,聚焦 ...

  3. 2019 篇 - 分享数百个 HT的工业互联网 2D 3D 可视化应用案例

    继<分享数百个 HT 工业互联网 2D 3D 可视化应用案例>2018 篇,图扑软件定义 2018 为国内工业互联网可视化的元年后,2019 年里我们与各行业客户进行了更深度合作,拓展了H ...

  4. C#设计模式04——工厂方法的写法

    1. What是C#工厂方法?C#工厂方法是一种设计模式,它通过创建具有相同基类的对象来实现代码的重用和灵活性. 2. Why使用C#工厂方法?使用C#工厂方法有以下好处:- 降低了代码的耦合性,让代 ...

  5. KVM 核心功能:内存虚拟化

    1 内存虚拟化简介 QEMU-KVM 提供内存的虚拟化,从虚拟机角度看其自身拥有的内存就是真实的物理内存.实际上,虚拟机是 host 上的一个 qemu 进程,在为虚拟机指定内存时,host 上并没有 ...

  6. Skywalking 搭建 nacos 注册中心及mysql 存储的集群架构

    本文为博主原创,未经允许不得转载 Skywalking 集群是将skywalking oap作为一个服务注册到nacos上,只要skywalking oap服务没有全部宕机,保证有一个skywalki ...

  7. 12-异步FIFO

    1.异步FIFO的应用 跨时钟域 批量数据 传输效率高 2.异步FIFO结构 FIFO深度 - 双端口RAM设计 3.异步FIFO深度计算 4.异步FIFO读写地址的编码 5.异步FIFO读写时钟域的 ...

  8. 【C/C++】知识点笔记

    1 - 联合体内嵌结构体初始化赋值 union { struct { int i; float f; char *p; }; int o; } obj3 = { 1, 2.2, "sk&qu ...

  9. [转帖]Linux下非oracle用户如何使用系统认证方式登陆数据

    https://www.cnblogs.com/kerrycode/p/17772866.html Linux系统中,DBA一般使用oracle用户登陆/访问Linux操作系统,然后使用sqlplus ...

  10. [转帖]Prometheus-使用python开发exporter

    exporter有很多,但想要特定需求的话,还需自行开发.在这里使用python写一个exporter,用于监控/root下的目录数量. 开发exporter需要使用prometheus_client ...