自用随便记录
C++
排序
stl
头文件
全能头文件:
#include<bits/stdc++.h>
自定义排序函数
bool compare(const int &odd1,const int &odd2)
{
return odd1>odd2;
}
priority_queuepq,如果是最小堆,就greater,重载运算符>。
测试:
priority_queue<int,vector<int>,greater<int>>pq;
for(int i = 0; i < 4; i++) pq.push(i);
printf("%d\n", pq.top());
>>> 0
或者自定义比较函数结构体
struct cmp{
bool operator()(const Node& x, const Node& y){
return x.p < y.p;
}
};
stl
枚举map
map<int, string> mapStudent;
mapStudent.insert(pair<int, string>(1, "student_one"));
mapStudent.insert(pair<int, string>(2, "student_two"));
mapStudent.insert(pair<int, string>(3, "student_three"));
map<int, string>::reverse_iterator iter;
for(iter = mapStudent.rbegin(); iter != mapStudent.rend(); iter++)
{
cout<<iter->first<<" "<<iter->second<<endl;
}
bitset
bitset<30>b(123);//123的二进制
b.any();
b.none();
b.count();
b.test(pos);
b.set();
b.set(pos);
b.reset();
b.reset(pos);
b.to_ulong();
优先队列
算法
堆
最短路
dijkstra
int d[maxn];
int pre[maxn];
int cost[maxn][maxn];
bool vis[maxn];
void dijkstra(int s, int n){
memset(d, -1, sizeof(d));
memset(pre, -1, sizeof(pre));
for(int i = 1; i <= n; i++){
d[i] = cost[s][i];
}
vis[s] = true;
d[s] = 0;
pre[s] = -1;
for(int _t = 1; _t < n; _t ++){
int k = -1;
for(int i = 1; i <= n; i++){
if(vis[i]) continue;
if(k == -1 || d[i] < d[k]) k = i;
}
if(k == -1) break;
vis[k] = true;
for(int i = 1; i <= n; i++){
if(vis[i])continue;
if(cost[k][i] == -1) continue;
int new_d = d[k] + cost[k][i];
if(d[i] == -1 || new_d < d[i]){
d[i] = new_d;
pre[i] = k;
}
}
}
}
floyd
void floyd(){
for(int k = 1; k <= n; k++){
for(int i = 1; i <= n;i++){
for(int j = 1; j <= n; j++){
d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
}
}
}
}
bellman-ford. 循环N-1次,对每条边松弛。如果第N次循环还可以松弛说明有负环。
并查集
https://leetcode.cn/problems/number-of-provinces/description/
const int maxn = 200+10;
class Solution {
public:
int fa[maxn];
int get_fa(int x){
if(fa[x] == x) return x;
fa[x] = get_fa(fa[x]);
return fa[x];
}
int findCircleNum(vector<vector<int>>& isConnected) {
int n = isConnected.size();
for(int i = 1; i <= n; i++) fa[i] = i;
for(int i = 0; i < n ;i++){
for(int j = i; j < n;j++){// i < j
if(isConnected[i][j] == 1){
int fi = get_fa(i);
int fj = get_fa(j);
fa[fj] = fi;
}
}
}
int num = 0;
for(int i = 0; i < n; i++){
if(i == get_fa(i)) num += 1;
//printf("i:%d, fa:%d\n", i, get_fa(i));
}
return num;
}
};
生成树
https://www.luogu.com.cn/problem/P3366
Kruscal
#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 10;
int N, M;
struct Edge{
int x, y, z;
Edge(){
}
Edge(int _x, int _y, int _z){
x = _x;
y = _y;
z = _z;
}
bool operator < (const Edge e){
return z < e.z;
}
};
Edge e[maxn];
bool vis[maxn];
int fa[maxn];
int get_fa(int x){
if(fa[x] == x) return x;
fa[x] = get_fa(fa[x]);
return fa[x];
}
void merge(int x, int y){
int fx = get_fa(x);
int fy = get_fa(y);
fa[fx] = fy;
}
int main(){
scanf("%d %d", &N, &M);
for(int i = 1; i <= M; i++){
int x, y, z;
scanf("%d %d %d", &x, &y, &z);
e[i] = Edge(x, y, z);
}
sort(e+1, e+1+M);
for(int i = 1; i <= N; i++) fa[i] = i;
int cost = 0;
for(int i = 1; i <= M; i++){
int x = e[i].x;
int y = e[i].y;
int fx = get_fa(x);
int fy = get_fa(y);
if(fx == fy) continue;
cost += e[i].z;
merge(x, y);
}
int vis_node = 0;
for(int i = 1; i <= N; i++) if(fa[i] == i) vis_node += 1;
if(vis_node == 1) printf("%d\n", cost);
else printf("orz\n");
return 0;
}
prim
#include <bits/stdc++.h>
using namespace std;
const int maxn = 4e5 + 10;
int N, M;
struct Edge{
int x, y, z;
Edge(){
}
Edge(int _x, int _y, int _z){
x = _x;
y = _y;
z = _z;
}
bool operator < (const Edge e){
return z < e.z;
}
};
Edge e[maxn];
int node2e[maxn];
int nex[maxn];
int d[maxn];
bool vis[maxn];
void add_edge(int node, int edge_id){
if(node2e[node] != -1) nex[edge_id] = node2e[node];
node2e[node] = edge_id;
}
int main(){
memset(node2e, -1, sizeof(node2e));
memset(nex, -1, sizeof(nex));
scanf("%d %d", &N, &M);
for(int i = 1; i <= M; i++){
int x, y, z;
scanf("%d %d %d", &x, &y, &z);
e[i] = Edge(x, y, z);
e[i+M] = Edge(y, x, z);
add_edge(x, i);
add_edge(y, i+M);
}
memset(d, -1, sizeof(d));
memset(vis, false, sizeof(vis));
int start = 1;
vis[start] = true;
for(int i = node2e[start]; i != -1; i = nex[i]){
d[e[i].y]= e[i].z;
}
int cost = 0;
bool yes = true;
for(int t = 1; t <= N-1; t++){
int k = -1;
for(int i = 1; i <= N; i++){
if(vis[i]) continue;
if(k == -1 || d[i] < d[k]) k = i;
}
if(k == -1){
yes = false;
break;
}
vis[k] = true;
cost += d[k];
for(int i = node2e[k]; i != -1; i = nex[i]){
int y = e[i].y;
if(vis[y]) continue;
if(d[y] == -1 || e[i].z < d[y]) d[y] = e[i].z;
}
}
if(yes) printf("%d\n", cost);
else printf("orz\n");
return 0;
}
数据结构
堆
图
树状数组
int tree[maxn<<2];
int lowbit(int x){
return x & -x;
}
int get_sum(int idx){
int sum = 0;
while(idx){
sum += tree[idx];
idx -= lowbit(x);
}
return sum;
}
void update(int idx, int value){
while(idx < LIMIT){
tree[idx] += value;
idx += lowbit(idx);
}
}
数学
快速幂
gcd和最小公倍数(ab的最小公倍数=ab/gcd(ab))
int gcd(int x, int y){
if(x<y) return gcd(y, x);
return y == 0?x:gcd(y, x%y);
}
质数
const int limit = 1e5 + 10;
bool visp[maxn];
int prime[maxn];
int p_cnt;
void get_prime(){
memset(visp, false, sizeof(visp));
for(int i = 2; i <= limit; i++){
if(!visp[i]) prime[++p_cnt] = i;
for(int j = 1; j <= p_cnt; j++){
if(i*prime[j] > limit) break;
visp[i*prime[j]] = true;
if(i % prime[j] == 0) break;
}
}
}
ex_gcd
几何
点积和叉积。
假设有两个二维向量v1(x1, y1)和v2(x2, y2)
点积:
https://blog.csdn.net/apr15/article/details/106160407
v
1
⃗
⋅
v
2
⃗
=
x
1
x
2
+
y
1
y
2
\vec{v_1}\cdot \vec{v_2} = x_1x_2+y_1y_2
v1⋅v2=x1x2+y1y2
v
1
⃗
⋅
v
2
⃗
\vec{v_1}\cdot \vec{v_2}
v1⋅v2的几何意义是:
v
1
⃗
\vec{v_1}
v1在
v
2
⃗
\vec{v_2}
v2上的投影,即:
v
1
⃗
⋅
v
2
⃗
=
∣
v
1
⃗
∣
∗
∣
v
2
⃗
∣
×
cos
θ
\vec{v_1}\cdot \vec{v_2}=|\vec{v_1}|*|\vec{v_2}|\times \cos\theta
v1⋅v2=∣v1∣∗∣v2∣×cosθ
叉积:
v
1
⃗
×
v
2
⃗
=
x
1
y
1
−
x
2
y
1
=
∣
v
1
⃗
∣
∗
∣
v
2
⃗
∣
×
sin
θ
\vec{v_1}\times \vec{v_2} = x_1y_1-x_2y_1=|\vec{v_1}|*|\vec{v_2}|\times \sin\theta
v1×v2=x1y1−x2y1=∣v1∣∗∣v2∣×sinθ
易得,
∣
v
1
⃗
×
v
2
⃗
∣
|\vec{v_1}\times \vec{v_2}|
∣v1×v2∣为两个向量共起点的时候构成的平行四边形的面积。
三维向量同理:

排序
https://www.luogu.com.cn/problem/P1177
https://leetcode.cn/problems/sort-an-array/description/
快速排序
思路:(假设数组从1开始到n)
- 每次确定一个pos,和最左边的数据交换(使得快排时的pos始终是最左边的),数值为posv。
- 双指针l和r指向1和n,要求最后posv左边的值都小于等于posv,右边的值都大于等于posv,最后posv的值为p。
- 因为需要最后确定位置p,如果循环是while(l<r),初始值l永远不能到达n+1。对于循环过程
while(??? &&v[l]<=posv)l++;,跳出循环的可能是v[l]>posv,v[l-1]<=posv,因此p可以是l-1。而如果l不能到达n+1,l-1就不能到达n,这是不合理的。所以循环应该为while(l<=r) - 代码如下:
void _kuaipai(int l, int r){
if(l>=r) return;
int LL=l, RR=r;
int pos = LL + (r-l)/2;
swap(v[l], v[pos]);
int posv = v[l];
while(l<=r){
while(l<=r && v[l]<=posv)l++;
while(l<=r && v[r]>=posv)r--;
if(l<=r) swap(v[l], v[r]);
}
// v[l]> posv || l==n+1
int p = l-1;
swap(v[LL], v[p]);
_kuaipai(LL, p-1);
_kuaipai(p+1, RR);
}
超时问题:比如数组长度为1000,所有数据都相同都是5。那么每次p都在最后一个数,复杂度为O(n^2)。
参考力扣的一种题解,可以把小于等于posv的放在左边,大于posv的放在右边。然后对左边再做一次快排,把小于posv的放左边,等于posv的放右边。
#include<bits/stdc++.h>
#include <cstdlib>
#include <ctime>
using namespace std;
const int maxn = 1e5 + 10;
int n;
int v[maxn];
void output(int l, int r){
for(int i = l; i <= r; i++){
printf("%d", v[i]);
if(i != r) printf(" ");
else printf("\n");
}
}
void _swap(int &a, int&b){
int tmp = a;
a = b;
b = tmp;
}
int _sub_kuaipai(int l, int r){
int posv = v[r];
_swap(v[l], v[r]);// v[r] == posv
while(l<=r){
while(l<=r && v[l]<posv)l++;//l==n+1 || v[l]>=posv
while(l<=r && v[r]>=posv)r--;
if(l<=r) _swap(v[l], v[r]);
}
// v[l-1] < posv
return l-1;
}
void _kuaipai(int l, int r){
if(l>=r) return;
int LL=l, RR=r;
srand(time(0));
int tmp = rand() % (r-l+1);
int pos = LL + tmp;
swap(v[l], v[pos]);
int posv = v[l];
while(l<=r){
while(l<=r && v[l]<=posv)l++;//l==n+1 || v[l]>posv
while(l<=r && v[r]>posv)r--;
if(l<=r) _swap(v[l], v[r]);
}
// v[l]> posv || l==n+1
int p = l-1;
_swap(v[LL], v[p]);
int p1 = _sub_kuaipai(LL, p);
// printf(">>> L:%d, R:%d, posv:%d, p:%d\n", LL, RR, posv, p);
// output(LL, RR);
_kuaipai(LL, p1);
_kuaipai(p+1, RR);
}
void kuaipai(){
_kuaipai(1, n);
}
int main(){
scanf("%d", &n);
for(int i = 1; i <= n; i++) scanf("%d", &v[i]);
kuaipai();
output(1, n);
return 0;
}
堆排序
#include<bits/stdc++.h>
#include <cstdlib>
#include <ctime>
using namespace std;
const int maxn = 1e5 + 10;
int n;
int v[maxn];
void output(int l, int r){
for(int i = l; i <= r; i++){
printf("%d", v[i]);
if(i != r) printf(" ");
else printf("\n");
}
}
void _swap(int &a, int&b){
int tmp = a;
a = b;
b = tmp;
}
int hp[maxn];
void add_value(int num, int val){// 第num个数为val
int p = num;
hp[num] = val;
while(1){
int fa = p>>1;//3-1,2-1
if(fa == 0) break;
if(hp[p]<=hp[fa]) break;
else{
_swap(hp[p], hp[fa]);
p = fa;
}
}
}
void duipai(){
// 构建最大堆
for(int i = 1; i <= n; i++){
add_value(i, v[i]);
}
//for(int i = 1; i <= n; i++) printf("%d\n", hp[i]);
// 排序
for(int i = n; i >= 2; i--){
int num = i-1;
_swap(hp[1], hp[i]);
// 下沉hp[1];
int p = 1;
while(p <= num){
int ls = p<<1;
int rs = p<<1|1;
if(ls>num) break;
int idx = ls;
if(rs<=num && hp[rs] > hp[idx]) idx = rs;
if(hp[p] < hp[idx]){
_swap(hp[p], hp[idx]);
p = idx;
}
else{
break;
}
}
}
for(int i = 1; i <= n; i++) v[i] = hp[i];
}
int main(){
scanf("%d", &n);
for(int i = 1; i <= n; i++) scanf("%d", &v[i]);
duipai();
output(1, n);
return 0;
}
归并排序
#include<bits/stdc++.h>
#include <cstdlib>
#include <ctime>
using namespace std;
const int maxn = 1e5 + 10;
int n;
int v[maxn];
void output(int l, int r){
for(int i = l; i <= r; i++){
printf("%d", v[i]);
if(i != r) printf(" ");
else printf("\n");
}
}
void _swap(int &a, int&b){
int tmp = a;
a = b;
b = tmp;
}
int temp[maxn];
void _merge(int l, int r){
if(l>=r) return;
int p = (l+r)>>1;
_merge(l, p);
_merge(p+1, r);
for(int i = l; i <= r; i++) temp[i] = v[i];
int p1 = l, p2 = p+1;
int idx = l;
while(p1<=p && p2<=r){
if(temp[p1] < temp[p2]) v[idx++] = temp[p1++];
else v[idx++] = temp[p2++];
}
while(p1<=p)v[idx++] = temp[p1++];
while(p2<=r)v[idx++] = temp[p2++];
}
void merge_sort(){
_merge(1, n);
}
int main(){
scanf("%d", &n);
for(int i = 1; i <= n; i++) scanf("%d", &v[i]);
merge_sort();
output(1, n);
return 0;
}
字符串
manacher
找最长回文子串
void initialize(int n, char ch[maxn]){
int nn = n<<1|1;
for(int i = nn-1, j=n-1; i>=2; i-=2){
ch[i] = '#';
ch[i-1] = ch[j];
}
ch[0] = '#';
}
void manacher(int n, char ch[maxn]){
memset(d, 0, sizeof(d));//d[i]是不包括i在内的半径
int mid = -1;
int maxr = -1;
for(int i = 0; i < n; i++){
if(maxr>d[i]){
int other = mid * 2 - i;
d[i] = min(d[other], maxr-i);
}
while(i-d[i]>=0 && i+d[i]<n && ch[i-d[i]]==ch[i+d[i]])i++;
d[i]--;
if(i+d[i]>maxr){
mid = i;
maxr = i+d[i];
}
}
}
kmp
模式匹配
前缀函数https://oi-wiki.org/string/kmp/
特点1:“一个重要的观察是 相邻的前缀函数值至多增加 1。”
特点2:当不符合最优的增加1的情况的时候,如何快速找到下一个可以匹配的对象?
注意 前缀数组pi[0]=0!!!
其他情况下 表示的是重复前后缀的长度,比如对于abab字符串,pi[3]=2(有重复串ab)
KMP:给定一个文本 t 和一个字符串 s,我们尝试找到并展示 s 在 t 中的所有出现(occurrence)
力扣测试题:https://leetcode.cn/problems/find-the-index-of-the-first-occurrence-in-a-string/description/
const int maxn = 1e4 + 10;
class Solution {
public:
int pi[maxn];//前缀数组
void get_pi(string s){
int n = s.length();
memset(pi, 0, sizeof(pi));
for(int i = 1; i < n; i++){
int j = pi[i-1];
while(j != 0 && s[j] != s[i]){
j = pi[j-1];
}
if(s[i] == s[j]) pi[i] = j+1;
else pi[i] = 0;
}
}
int strStr(string haystack, string needle) {
int n_needle = needle.length();
get_pi(needle);
int n = haystack.length();
int j = 0;
for(int i = 0; i < n; i++){
while(j != 0 && haystack[i] != needle[j]){
j = pi[j-1];
}
if(haystack[i] == needle[j]){
j++;
}
//printf("i:%d, ch:%c, j:%d, chj:%c\n", i, haystack[i], j, needle[j]);
if(j == n_needle) return i - n_needle + 1;
}
return -1;
}
};
&spm=1001.2101.3001.5002&articleId=145740196&d=1&t=3&u=e9570ee0527749a9aae8e93308374232)
8510

被折叠的 条评论
为什么被折叠?



