题目链接:初始化

这种 ynoi 的老题就是卡常。来简单说说这题的思维切入口。

看到形如 \(y+k \times x\) 的结构,自然而然思考一下如果我们是暴力更新会有怎么样的效果。我们容易发现,如果 \(x\) 比较大,暴力更新的次数 \(\dfrac{n}{x}\) 也不会很大的,但 \(x\) 如果很小,那么就会更新次数很大了。这启发我们按 \(x\) 的大与小两种情况进行各自地优化处理。那么这个思想其实就是“根号分治思想”:

  1. 对 \(x > \sqrt{n}\) 的修改,进行暴力更新,同时维护块区间之和,这里复杂度为 \(\sqrt{n}\)。

  2. 对 \(x \le \sqrt{n}\) 的修改,我们另寻途径,优化它的复杂度。

怎么解决小步长呢,我们容易发现如果每次都是 \(+x\) 以后的位置进行修改,如果我们的块长 等于 \(x\) 就好了。这样一来,对于块长为 \(x\) 的区间,你会发现每个区间同样的相对位置发生修改了。

我们可以发现每个块的变化都是一致的,都是同一个块同一个位置发生单点变化,同时我们又注意到此时此刻不同长度的 \(x\) 显然数量不超过 \(\sqrt{n}\),这启发我们为每一种不同块长维护一个代表块的信息。

我们抽象地拿出一块作为代表块,观察它的信息。

对于每个不同长度的块,为了知道在查询时它们对应的块和,但同时注意到每个整块对应的样子都是一样的,这启发我们可以维护块内前缀和,而拿到每个块内之和。当然我们注意到分块的查询的特点:偶尔会有散块查询。

容易发现散块,我们可以用前缀和作差算出来,但由于涉及到需要计算当前块的左右端点下标,我们为了方便的书写,可以同时维护块后缀和,使得代码层面上更易理解,即 \(L\) 到它对应的块右端点之和显然为 \(suf_L\) 后缀和。这样一来,我们就能知道步长为 \(x\) 的每个整块内的情况了。同时我们注意到 \(y<=x\) ,所以 起点一定是在第一个块的,每个块情况是一模一样的。

卡常细节

首先由于具有取模操作,所以我们可以考虑用先全部加起来,最后再取模。另外注意到每次遍历不同块长的 \(x\) 的前后缀和情况,有些 \(x\) 可能并未出现过,所以我们可以记录下出现过的块长在哈希表中用于遍历使用。最后可以考虑上快读之类的东西。对于原数组如果未发生大块修改,可以直接前缀和求区间和。

参照代码
#include <bits/stdc++.h>

//#pragma GCC optimize("Ofast,unroll-loops")

#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 = 2e5 + 10;
constexpr int MOD = 1e9 + 7;
constexpr int Size = sqrt(N) + 1;
constexpr int Cnt = (N + Size - 1) / Size + 1;
#define pointPos(t,x) ((t-1)%x+1) //求出某个位置在指定块长中应该对应的块内编号
#define blockId(t,x) ((t-1)/x+1) //求出某个位置在指定块长对应块编号
unordered_set<int> vis; //出现过的块长
int cnt, siz;
int pre[Size][Size], suf[Size][Size];//不同块长内部的前后缀和
int a[N];
int n, q;
int s[N], e[N];//块的起点和
int sum[Cnt]; //块和
int OldPre[N];//原数组的前缀和
bool isBigUpdate; inline void BigUpdate(const int x, int y, const int z)
{
for (; y <= n; y += x)
{
const int id = blockId(y, siz);
a[y] = (a[y] + z) % MOD, sum[id] = (sum[id] + z) % MOD;
}
} inline void SmallUpdate(const int x, const int y, const int z)
{
forn(i, 1, y)suf[x][i] = (suf[x][i] + z) % MOD;
forn(i, y, x)pre[x][i] = (pre[x][i] + z) % MOD;
} inline int OldQuery(const int l, const int r)
{
const int L = blockId(l, siz), R = blockId(r, siz);
ll ans = 0;
if (L == R)
{
forn(i, l, r)ans += a[i];
return ans % MOD;
}
forn(i, l, e[L])ans += a[i];
forn(i, s[R], r)ans += a[i];
forn(i, L+1, R-1)ans += sum[i];
return ans % MOD;
} inline int Query(const int l, const int r)
{
ll ans = isBigUpdate ? OldQuery(l, r) : OldPre[r] - OldPre[l - 1];
//遍历每一种块长
for (auto x : vis)
{
const int L = blockId(l, x), R = blockId(r, x);
const int Lpos = pointPos(l, x), Rpos = pointPos(r, x);
if (L == R)ans += pre[x][Rpos] - pre[x][Lpos - 1];
else ans += ll(R - L - 1) * pre[x][x] + suf[x][Lpos] + pre[x][Rpos];
}
return modt(ans, MOD);
} inline void solve()
{
read(n, q);
siz = sqrt(n);
cnt = (n + siz - 1) / siz;
forn(i, 1, n)read(a[i]), OldPre[i] = (OldPre[i - 1] + a[i]) % MOD;
forn(i, 1, cnt)s[i] = (i - 1) * siz + 1, e[i] = i * siz;
e[cnt] = n;
forn(i, 1, cnt)forn(j, s[i], e[i])sum[i] = (sum[i] + a[j]) % MOD;
forn(i, 1, q)
{
int op;
read(op);
if (op == 1)
{
int x, y, z;
read(x, y, z);
if (x > siz)BigUpdate(x, y, z), isBigUpdate = true;
else SmallUpdate(x, y, z), vis.insert(x);
}
else
{
int l, r;
read(l, r);
write(endl, Query(l, r));
}
}
} signed int main()
{
Spider
//------------------------------------------------------
int test = 1;
// read(test);
// cin >> test;
forn(i, 1, test)solve();
// while (cin >> n, n)solve();
// while (cin >> test)solve();
}
\[ 最终时间理论最坏复杂度为\ O((n+q)\sqrt{n})
\]

P5309 [Ynoi2011] 初始化 题解的更多相关文章

  1. 从 洛谷P5309 Ynoi2011 初始化 看卡常

    一般情况下,程序运行消耗时间主要与时间复杂度有关,超时与否取决于算法是否正确. 但对于某些题目,时间复杂度正确的程序也无法通过,这时我们就需要卡常数,即通过优化一些操作的常数因子减少时间消耗. 比如这 ...

  2. [Ynoi2011]初始化 题解

    第一道Ynoi,纪念一下. 众所周知,Ynoi会进行惨无人道的卡常操作,所以我们可以使用暴力去做Ynoi. 于是乎,我们考虑分块+暴力. 对于操作2,不难发现是道裸的分块,可以抄P3372的代码. 对 ...

  3. 洛谷P5309 Ynoi 2011 初始化 题解

    题面. 我也想过根号分治,但是题目刷得少,数组不敢开,所以还是看题解做的. 这道题目要用到根号分治的思想,可以看看这道题目和我的题解. 题目要求处理一个数组a,支持如下操作. 对一个整数x,对数组长度 ...

  4. 题解 洛谷 P5311 【[Ynoi2011]成都七中】

    每次询问是关于 \(x\) 所在的连通块,所以考虑用点分树来解决本题. 点分树上每个节点所对应的子树,都是原树中的一个连通块.询问中给定 \(x\) 和区间 \([l,r]\),其就已经确定了原树的一 ...

  5. poj2391 Ombrophobic Bovines 题解

    http://poj.org/problem?id=2391 floyd+网络流+二分 题意:有一个有向图,里面每个点有ai头牛,快下雨了牛要躲进雨棚里,每个点有bi个雨棚,每个雨棚只能躲1头牛.牛可 ...

  6. LeetCode OJ 题解

    博客搬至blog.csgrandeur.com,cnblogs不再更新. 新的题解会更新在新博客:http://blog.csgrandeur.com/2014/01/15/LeetCode-OJ-S ...

  7. 2017 google Round D APAC Test 题解

    首先说明一下:我只是用暴力过了4道题的小数据,就是简单的枚举,大数据都不会做!下面的题解,是我从网上搜到的解答以及查看排行榜上大神的答案得出来的. 首先贴一下主要的题解来源:http://codefo ...

  8. HDU2094(产生冠军)题解

    HDU2094(产生冠军)题解 以防万一,题目原文和链接均附在文末.那么先是题目分析: [一句话题意] 根据给定现有比赛结果推断分析冠军.(这描述...我建议还是看题吧,题不长) [题目分析] 给出的 ...

  9. Java JVM 类的连接与初始化 [ 转载 ]

    Java类的连接与初始化 (及2013阿里初始化笔试题解析)  转自http://www.cnblogs.com/iceAeterNa/p/4876747.html         Java虚拟机通过 ...

  10. 2015浙江财经大学ACM有奖周赛(一) 题解报告

    2015浙江财经大学ACM有奖周赛(一) 题解报告 命题:丽丽&&黑鸡 这是命题者原话. 题目涉及的知识面比较广泛,有深度优先搜索.广度优先搜索.数学题.几何题.贪心算法.枚举.二进制 ...

随机推荐

  1. 源码深度解析 Handler 机制及应用

    本文以源码分析+实际应用的形式,详细讲解了 Handler 机制的原理,以及在开发中的使用场景和要注意的地方. 一.基本原理回顾 在 Android 开发中,Handler及相关衍生类的应用经常用到, ...

  2. 阿里云 Serverless 应用引擎(SAE)2

    8月7日,阿里云 Serverless 应用引擎(SAE)2.0正式公测上线!全面升级后的SAE 2.0具备极简体验.标准开放.极致弹性三大优势,应用冷启动全面提效,秒级完成创建发布应用,应用成本下降 ...

  3. SpringCloud学习 系列八、OpenFeign

    系列导航 SpringCloud学习 系列一. 前言-为什么要学习微服务 SpringCloud学习 系列二. 简介 SpringCloud学习 系列三. 创建一个没有使用springCloud的服务 ...

  4. vue学习笔记 十四、页面跳转

    系列导航 vue学习笔记 一.环境搭建 vue学习笔记 二.环境搭建+项目创建 vue学习笔记 三.文件和目录结构 vue学习笔记 四.定义组件(组件基本结构) vue学习笔记 五.创建子组件实例 v ...

  5. offline RL | ABM:从 offline dataset 的好 transition 提取 prior policy

    ICLR 2020,6 6 6. 材料: 论文题目:Keep Doing What Worked: Behavior Modelling Priors for Offline Reinforcemen ...

  6. 使用WTM框架创建博客系统后台并在云服务器发布

    阅读导航 关于lqclass.com 博客后台前后端部署 2.1 已部署访问链接 2.2 nginx 部署 2.2.1 后台后端发布 2.2.2 后台前端发布 2.2.3 云服务器部署 下次分享 1. ...

  7. 使用华为路由连接WiFi,被限制网速?

    1.问题 使用华为路由连接WiFi,但是网速非常慢,经常半天才能加载一个界面? 2.解决方法 登陆http://192.168.3.1/网址,发现限速一栏被框选,取消即可

  8. [转帖]Shell脚本中利用expect实现非交互式

    https://developer.aliyun.com/article/885723?spm=a2c6h.24874632.expert-profile.295.7c46cfe9h5DxWK 简介: ...

  9. [转帖]java -d 参数(系统属性) 和 环境变量

    https://www.cnblogs.com/limeiyang/p/16565920.html 1. -d 参数说明 通过 java -h 查看可知: 注意:-D= : set a system ...

  10. [转贴]细说:Unicode, UTF-8, UTF-16, UTF-32, UCS-2, UCS-4

    细说:Unicode, UTF-8, UTF-16, UTF-32, UCS-2, UCS-4 https://www.cnblogs.com/malecrab/p/5300503.html 1. U ...