当前位置: 首页 > news >正文

【思维】根号分治

写在前面的话:

个人理解 根号分治本身就是一种卡着评测机过题的做法,所以非必要不要写 #define int long long !!!


本篇博客参考:暴力美学——浅谈根号分治

做到过两三题根号分治了,来总结一下这个算法

与其说是算法,不如说是一种思维

根号分治的主要思路是,数据范围很大的时候(指不能接受 n 2 n^2 n2 复杂度,但可以接受 n n n\sqrt n nn 复杂度的情况,通常是 1 e 8 − 1 e 9 1e8-1e9 1e81e9),将数据分为两个部分,一个是小于 n \sqrt n n 的部分,一个是大于等于 n \sqrt n n 的部分,两个部分分别采用不同的处理方式:

  • 第一个部分(需要处理的间隔小的部分),使用技巧计算,例如前缀和等预处理算法
  • 第二个部分(需要处理的间隔大的部分),暴力计算

下面举例说明几个可以使用根号分治的场景

    • 数据结构
    • 数论

数据结构

来一道例题:F. Remainder Problem

题目意思是,给出一个长度为 5 e 5 5e5 5e5 的序列,初始值都是 0,给出 q 组操作,每组操作包括 op x y

  • op == 1 时,a[x] += y
  • op == 2 时,输出下标模 x 等于 y 的位置的值之和

我们可以想到两种做法:

  1. 暴力处理,第一个操作就直接加,复杂度 O ( 1 ) O(1) O(1),第二个操作就遍历一遍数组,复杂度 O ( n ) O(n) O(n),这样最坏的复杂度是 O ( n q ) O(nq) O(nq),T
  2. 利用二维数组预处理,b[i][j] 表示模 i 等于 j 的位置上的值之和,第一个操作就遍历更新 b[i][j],复杂度 O ( n ) O(n) O(n),第二个操作直接输出,复杂度 O ( 1 ) O(1) O(1),最坏的复杂度是 O ( n q ) O(nq) O(nq),T

那能不能把两者结合起来呢?

我们发现如果 x 比较大的话,暴力处理的第二个操作复杂度就不会太高,但是不能进行预处理(空间上不能接受),x 比较小的话,可以进行预处理,而暴力操作的复杂度就会比较高

说到这里就清楚啦:x 大就第一个做法,x 小就第二个做法,大小的分界线是什么呢?就是 n \sqrt n n

c o d e code code

#include <bits/stdc++.h>using namespace std;// #define int long long
using i64 = long long;typedef pair<int, int> PII;
typedef pair<int, char> PIC;
typedef pair<double, double> PDD;
typedef pair<int, PII> PIII;
typedef pair<int, pair<int, bool>> PIIB;const int N = 5e5 + 10;
const int maxn = 710;
const int mod = 1e9 + 7;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;int a[N], b[710][710];void solve()
{int q;cin >> q;while (q -- ){int op, x, y;cin >> op >> x >> y;if (op == 1){a[x] += y;for (int i = 1; i < 700; i ++ ) b[i][x % i] += y;}else{if (x < 700) cout << b[x][y] << '\n';else{int res = 0;for (int i = y; i <= 5e5; i += x) res += a[i];cout << res << '\n';}}}
}signed main()
{ios::sync_with_stdio(false);cin.tie(0), cout.tie(0);int t = 1;// cin >> t;while (t--){solve();}
}

数论

看这题:D. Two Arithmetic Progressions

题目给出这样的两个数列:

  • a 1 k + b 1 a_1k+b_1 a1k+b1
  • a 2 k + b 2 a_2k+b_2 a2k+b2

k > = 0 k>=0 k>=0

然后给出 [ l , r ] [l,\ r] [l, r],问这个区间里有多少数同时存在于上面的两个数列里( a 、 b a、b ab 的范围都是 2 e 9 2e9 2e9

我们还是想出两种办法:

  • k 从 0 开始,枚举第一个数列的数,直到找到一个在第二个数列里也出现的数(可以发现最多找 max(a1, a2) 次),之后每次加上循环节(也就是 a 1 a_1 a1 a 2 a_2 a2 的最小公倍数)即可
  • 枚举 a a a 值较大的数列,符合条件就答案+1,完全暴力

maxx = max(a1, a2)

  • 当 maxx 比较大的时候,数列里的值的数量就会比较少,可以通过枚举解决问题,但使用第一种方法就会T

  • 当 maxx 比较小的时候,枚举会T,但可以使用第一种找循环节的方法

所以通过这个进行根号分治,结束!

(其实这题的正解并不是根号分治,但是使用这种思想可以直接碾过去cf2500的题!!好爽ovo)

c o d e code code

#include <bits/stdc++.h>using namespace std;#define int long long
using i64 = long long;typedef pair<int, int> PII;
typedef pair<int, char> PIC;
typedef pair<double, double> PDD;
typedef pair<int, PII> PIII;
typedef pair<int, pair<int, bool>> PIIB;const int N = 2e9;
const int maxn = 710;
const int mod = 1e9 + 7;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;void solve()
{int a1, b1, a2, b2, l, r;cin >> a1 >> b1 >> a2 >> b2 >> l >> r;int maxx = max(a1, a2);if (maxx < sqrt(N)) // 找最小公倍数{for (int i = 0; i <= maxx; i ++ ){int tmp = a1 * i + b1;if (abs(tmp - b2) % a2 == 0){int lcmm = lcm(a1, a2);int st = max({l, b1, b2});if (tmp < st){tmp += ((st - tmp) / lcmm + 1) * lcmm;tmp = st + (tmp - st) % lcmm;}else tmp = st + (tmp - st) % lcmm;if (tmp > r) continue;cout << (r - tmp) / lcmm + 1 << '\n';return;}}cout << 0 << '\n';}else // 暴力{int ans = 0;if (a1 < a2) swap(a1, a2), swap(b1, b2);for (int i = b1; i <= r; i += a1){if (i < l || i < b2) continue;if ((i - b2) % a2 == 0) ans ++ ;}cout << ans << '\n';}
}signed main()
{ios::sync_with_stdio(false);cin.tie(0), cout.tie(0);int t = 1;// cin >> t;while (t--){solve();}
}
http://www.lryc.cn/news/348512.html

相关文章:

  • Linux线程(三)死锁与线程同步
  • SpringAMQP 发布订阅-TopicExchange
  • uniapp h5 配置代理服务器
  • 使用Apache Spark从MySQL到Kafka再到HDFS的数据转移
  • 一篇文章拿下Redis 通用命令
  • 锂电池充电充放电曲线分析
  • vue3 第二十九节 (vue3 事件循环之nextTick)
  • 使用Flask-SocketIO构建实时Web应用
  • 可重构柔性装配产线:为工业制造领域注入了新的活力
  • 懒人网址导航源码v3.9
  • springboot 开启缓存 @EnableCaching(使用redis)
  • Adobe After Effects AE v24.3.0 解锁版 (视频合成及视频特效制作)
  • Qt---文件系统
  • ruoyi-vue-pro 使用记录(2)
  • centos7中如何全局搜索一下nginx的配置文件?
  • 2024年5月10日有感复盘
  • C++通过json文件配置参数
  • idea连接远程仓库
  • 初始Django
  • leetcode56--合并区间
  • 赋能数据库智能托管,Akamai 发布首款云计算业务线产品!
  • Go语言系统学习笔记(三):杂项篇
  • 黄仁勋炉边对话:创业的超能力与英伟达的加速计算之旅
  • .NET开源、功能强大、跨平台的图表库LiveChart2
  • 疯狂学英语
  • LeetCode //C - 93. Restore IP Addresses
  • 【数据结构】栈和队列OJ面试题
  • 【联邦学习——手动搭建简易联邦学习】
  • Springboot项目如何创建单元测试
  • Win10 如何同时保留两个CUDA版本并自由切换使用