如果有错误的话还希望各位巨巨评论指正……
目录
Pollard Rho+Miller Rabin:大素数判断和素因子分解
主席树:
可以求第K大的数
理解参考:https://www.cnblogs.com/LiuRunky/p/Sustainable_Segment_Tree.html
bin巨的板子放一下嘻嘻 (可以求区间[l,r]内第K小的数)
#include <stdio.h>
#include <math.h>
#include <bits/stdc++.h>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 100010;
const int M = maxn * 30;
int q, n, m, tot;
int a[maxn], t[maxn];
int T[maxn], lson[M], rson[M], c[M];
void Init_hash()
{
for (int i = 1; i <= n; i++) {
t[i] = a[i];
}
sort(t + 1, t + 1 + n);
m = unique(t + 1, t + 1 + n) - t - 1;
}
int build(int l, int r)
{
int root = tot++;
c[root] = 0;
if (l != r) {
int mid = (l + r) >> 1;
lson[root] = build(l, mid);
rson[root] = build(mid + 1, r);
}
return root;
}
int Hash(int x)
{
return lower_bound(t + 1, t + 1 + m, x) - t;
}
int update(int root, int pos, int val)
{
int newroot = tot++, tmp = newroot;
c[newroot] = c[root] + val;
int l = 1, r = m;
while (l < r) {
int mid = (l + r) >> 1;
if (pos <= mid) {
lson[newroot] = tot++;
rson[newroot] = rson[root];
newroot = lson[newroot];
root = lson[root];
r = mid;
} else {
rson[newroot] = tot++;
lson[newroot] = lson[root];
newroot = rson[newroot];
root = rson[root];
l = mid + 1;
}
c[newroot] = c[root] + val;
}
return tmp;
}
int query(int left_root, int right_root, int k)
{
int l = 1, r = m;
while (l < r) {
int mid = (l + r) >> 1;
if (c[lson[left_root]] - c[lson[right_root]] >= k) {
r = mid;
left_root = lson[left_root];
right_root = lson[right_root];
} else {
l = mid + 1;
k -= c[lson[left_root]] - c[lson[right_root]];
left_root = rson[left_root];
right_root = rson[right_root];
}
}
return l;
}
int main()
{
while (~scanf("%d%d", &n, &q)) {
tot = 0;
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
}
Init_hash();
T[n + 1] = build(1, m);
for (int i = n; i > 0; i--) {
int pos = Hash(a[i]);
T[i] = update(T[i + 1], pos, 1);
}
while (q--) {
int l, r, k;
scanf("%d%d%d", &l, &r, &k);
printf("%d\n", t[query(T[l], T[r + 1], k)]);
}
}
return 0;
}
线段树:
将数组构建成一棵二叉树,方便于区间查询,单点更新
看网上视频写的板子
#include <stdio.h>
#include <iostream>
#include <string.h>
#include <algorithm>
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 1e8 + 5;
int arr[maxn], tree[maxn];
void build(int node, int start, int emd)
{
if (start == emd) {
tree[node] = arr[start];
} else {
int mid = (start + emd) / 2;
int left_node = 2 * node + 1;
int right_node = 2 * node + 2;
build(left_node, start, mid);
build(right_node, mid + 1, emd);
tree[node] = tree[left_node] + tree[right_node];
}
}
void update(int node, int start, int emd, int idx, int val)
{
if (start == emd) {
arr[idx] = val;
tree[node] = val;
} else {
int mid = (start + emd) / 2;
int left_node = 2 * node + 1;
int right_node = 2 * node + 2;
if (idx >= start && idx <= mid) {
update(left_node, start, mid, idx, val);
} else {
update(right_node, mid + 1, emd, idx, val);
}
tree[node] = tree[left_node] + tree[right_node];
}
}
int query(int node, int start, int emd, int L, int R)
{
if (R < start || L > emd) {
return 0;
} else if (L <= start && R >= emd) {
return tree[node];
} else if (start == emd) {
return tree[node];
} else {
int mid = (start + emd) / 2;
int left_node = node * 2 + 1;
int right_node = node * 2 + 2;
int sum_left = query(left_node, start, mid, L, R);
int sum_right = query(right_node, mid + 1, emd, L, R);
return sum_left + sum_right;
}
}
int main()
{
int n, c, k;
scanf("%d%d%d", &n, &c, &k);
for (int i = 0; i < n; i++) {
scanf("%d", &arr[i]);
}
build( 0, 0, n - 1);// 建树
printf("%d\n", query(0, 0, n - 1, 2, 5));
//查询区间2,5之内的和
return 0;
}
最大流 = 最小割 :
从A地到B地有很多条路可以走 并且 每条路可能会有宽窄不同的地方(即权值不同)最大流就是从A地到B地 可以通过的最大流量的和 因为到比较窄的地方 就只能通过那么一些流量 即时后来路变宽了 还是那么点流量……
从最小割的理解看就是 使割掉的边的权值最小 然后使两点间没有通路 的边权之和
逆元:
因为 分数无法取模 这时候需要用到逆元 inv[b] 是 b 关于 p 的逆元 所以
威尔逊定理:
当且仅当p为素数时, (p - 1)! ≡ (-1) mod p
阶乘 :
N!= N*(N-1)*(N-2)……*2*1 注意 0!=1
快速幂:
通过二进制转换,将乘的次数分解,减少次数消耗的时间
快速乘:
与快速幂相似,比正常乘法快一些,也避免乘法过程中爆int / long long范围
Pollard Rho+Miller Rabin:大素数判断和素因子分解
//判断素数
bool Miller_Rabin(LL n)
{
if(n == 2) return true;
if(n < 2 || !(n & 1)) return false;
LL m = n - 1;
int k = 0;
while((m & 1) == 0)
{
k++;
m >>= 1;
}
for(int i=0; i<Times; i++)
{
LL a = rand() % (n - 1) + 1;
LL x = quick_mod(a, m, n);
LL y = 0;
for(int j=0; j<k; j++)
{
y = multi(x, x, n);
if(y == 1 && x != 1 && x != n - 1) return false;
x = y;
}
if(y != 1) return false;
}
return true;
}
//分解素数
LL pollard_rho(LL n, LL c)
{
LL i = 1, k = 2;
LL x = rand() % (n - 1) + 1;
LL y = x;
while(true)
{
i++;
x = (multi(x, x, n) + c) % n;
LL d = gcd((y - x + n) % n, n);
if(1 < d && d < n) return d;
if(y == x) return n;
if(i == k)
{
y = x;
k <<= 1;
}
}
}
一些数论知识:
https://zerol.me/2018/08/29/number-theory/
离散化:
将范围较大的有限个数据变成较小的数,使数据中的最大值尽可能小且保证所有数据都是正数。
理解参考:https://blog.youkuaiyun.com/qq_41754350/article/details/81199993
栗子:12342434 12312 234234 12342434
可以离散化变成 3 1 2 3
数据一下子变小了 比较也更容易
板子如下:
#include<algorithm>
#include <bits/stdc++.h>
//n 原数组大小 num 原数组中的元素 lsh 离散化的数组 cnt 离散化后的数组大小
using namespace std;
int main()
{
int lsh[MAXN] , cnt , num[MAXN] , n;
for(int i=1; i<=n; i++) {
scanf("%d",&num[i]);
lsh[i] = num[i];
}
sort(lsh+1 , lsh+n+1);
cnt = unique(lsh+1 , lsh+n+1) - lsh - 1;
for(int i=1; i<=n; i++)
num[i] = lower_bound(lsh+1 , lsh+cnt+1 , num[i]) - lsh;
for(int i=1; i<=n; i++)
printf("%d ",num[i]);
return 0;
}
在某个博客上看到了很神奇的操作
暂时没看明白 先贴上代码emm
struct Node{
int val, order;
}node[maxn];
for(int i=1; i<=n; i++) {
if(i==1 || node[i].val!= node[i-1].val) { //去重
r[node[i].order] = i;
}
}
来源:https://blog.youkuaiyun.com/qq_41754350/article/details/81199993
先酱~~