前言
存一些自己以前写的模板,方便自己找(PS:不断更新,有点懒,想到啥更新啥)
文章目录
一、数学
1. 二分
(见文章)
2. 快速幂
long long ksm(long long a, long long n, long long mod) {
long long ans = 1;
while(n) {
if(n & 1)
ans = (ans * a) % mod;
a = (a * a) % mod;
n >>= 1;
}
return ans % mod;
}
3. 筛素数
(1) 埃氏筛
//初始化都是素数
bool numlist[100000000];
int prime[2000001], cnt;
for(int i = 2; i <= N; ++i) {
if(numlist[i] == false){
prime[++cnt] = i ;
for(int j = i; i * j <= N; ++j) {
numlist[i * j] = true; // 不是素数标记 1
}
}
}
(2) 欧拉筛
#include <cstdio>
#include <cstring>
bool isPrime[100000010]; //isPrime[i] == 1表示:i是素数
int Prime[6000010], cnt = 0; //Prime存质数
void GetPrime(int n) //筛到n
{
memset(isPrime, 1, sizeof(isPrime)); //以“每个数都是素数”为初始状态,逐个删去
isPrime[1] = 0;//1不是素数
for(int i = 2; i <= n; i++)
{
if(isPrime[i])//没筛掉
Prime[++cnt] = i; //i成为下一个素数
for(int j = 1; j <= cnt && i*Prime[j] <= n/*不超上限*/; j++)
{
//从Prime[1],即最小质数2开始,逐个枚举已知的质数,并期望Prime[j]是(i*Prime[j])的最小质因数
//当然,i肯定比Prime[j]大,因为Prime[j]是在i之前得出的
isPrime[i*Prime[j]] = 0;
if(i % Prime[j] == 0)//i中也含有Prime[j]这个因子
break; //重要步骤。见原理
}
}
}
int main()
{
int n, q;
scanf("%d %d", &n, &q);
GetPrime(n);
while (q--)
{
int k;
scanf("%d", &k);
printf("%d\n", Prime[k]);
}
return 0;
}
二、最短路
1. floyd
void flody(){
for(int k = 0; k < n; ++k)
for(int i = 0; i < n; ++i)
for(int j = 0; j < n; ++j)
map[i][j] = min(map[i][j], map[i][k] + map[k][j]);
}
2. dijkstra(朴素版)
注意每个数组的初始化问题
(1) 核心代码
void dijkstra(int s){
memset(dis, inf, sizeof dis);
dis[s] = 0;
for(int i = 0; i < n; ++i){
int t = -1;
for(int j = 0; j < n; ++j)
if(!vis[j] && (t == -1 || dis[j] < dis[t]))
t = j;
vis[t] = 1;
for(int j = 0; j < n; ++j)
dis[j] = min(dis[j], dis[t] + map[t][j]);
}
}
(2) 多重判断 + 输出路径
#include <iostream>
#include <cstring>
using namespace std;
const int inf = 0x3f3f3f3f;
int map[550][550], vis[550], dis[550], path[550];
int a[550][550], sum[550];
int n, m, S, D;
void dijkstra(int s){
memset(dis, inf, sizeof dis);
dis[s] = 0;
for(int i = 0; i < n; ++i){
int t = -1;
for(int j = 0; j < n; ++j)
if(!vis[j] && (t == -1 || dis[j] < dis[t]))
t = j;
vis[t] = 1;
for(int j = 0; j < n; ++j){
if(dis[j] > dis[t] + map[t][j]){
dis[j] = dis[t] + map[t][j]; //更新最短距离
sum[j] = sum[t] + a[t][j]; //更新相应值
path[j] = t; //存路径
}
else if(dis[j] == dis[t] + map[t][j]){
if(sum[j] > sum[t] + a[t][j]){
sum[j] = sum[t] + a[t][j];
path[j] = t;
}
}
}
}
}
void dfs(int x){ //输出路径,注意是从后往前找
if(x == S){
printf("%d", x);
return;
}
dfs(path[x]);
printf(" %d", x);
}
int main() {
cin >> n >> m >> S >> D;
memset(map, inf, sizeof map);
for(int i = 0; i < n; ++i)
map[i][i] = 0;
while(m--){
int x, y, z1, z2;
cin >> x >> y >> z1 >> z2;
map[x][y] = map[y][x] = z1;
a[x][y] = a[y][x] = z2;
}
dijkstra(S);
dfs(D);
printf(" %d %d", dis[D], sum[D]);
}
3. spfa
解决负权边问题
#include <iostream>
#include <cstring>
#include <queue>
using namespace std;
const int inf = 0x3f3f3f3f, N = 2e5 + 10;
int e[N], w[N], ne[N], h[N], vis[N], dis[N], ret, n, m;
void add(int a, int b, int c) {
e[ret] = b;
w[ret] = c;
ne[ret] = h[a];
h[a] = ret++;
}
void spfa(int s) {
memset(dis, inf, sizeof dis);
dis[s] = 0;
queue<int> q;
q.push(s);
vis[s] = 1;
while(!q.empty()) {
int t = q.front();
q.pop();
vis[t] = 0;
for(int i = h[t]; i != -1; i = ne[i]){
int j = e[i];
if(dis[j] > dis[t] + w[i]){
dis[j] = dis[t] + w[i];
if(!vis[j]) {
q.push(j);
vis[j] = 1;
}
}
}
}
}
int main() {
memset(h, -1, sizeof h);
cin >> n >> m;
while(m--) {
int x, y, z;
cin >> x >> y >> z;
add(x, y, z);
}
spfa(1);
for(int i = 2; i <= n; ++i)
cout << dis[i] << endl;
}
4. 最小生成树
#include <iostream>
#include <cstring>
using namespace std;
const int inf = 0x3f3f3f3f;
int map[1010][1010], vis[1010], dis[1010], n, m;
int prim() {
memset(dis, inf, sizeof dis);
int sum = 0;
for(int i = 0; i < n; ++i) {
int t = -1;
for(int j = 1; j <= n; ++j)
if(!vis[j] && (t == -1 || dis[j] < dis[t]))
t = j;
vis[t] = 1;
if(i && dis[t] == inf)
return inf;
if(i)
sum += dis[t];
for(int j = 1; j <= n; ++j)
dis[j] = min(dis[j], map[t][j]);
}
return sum;
}
int main() {
memset(map, inf, sizeof map);
cin >> n >> m;
for(int i = 1; i <= n; ++i)
map[i][i] = 0;
while(m--) {
int x, y, z;
cin >> x >> y >> z;
map[x][y] = map[y][x] = min(map[x][y], z);
}
int sum = prim();
if(sum == inf) cout << -1;
else cout << sum;
}
三、搜索
1. dfs(深度优先搜素)
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
char a[520][520];
int vis[520][520];
int dir[4][2] = {1, 0, -1, 0, 0, 1, 0, -1};
int f, ex, ey, n, m, sx, sy;
void dfs(int x,int y) {
if(x == ex && y == ey){
f = 1; return;
}
for(int i = 0; i < 4; ++i) {
int xx = x + dir[i][0];
int yy = y + dir[i][1];
if(vis[xx][yy] == 1 || a[xx][yy]=='#' || xx < 0 || xx >= n || yy < 0 || yy >= m)
continue;
vis[xx][yy] = 1;
dfs(xx, yy);
//vis[xx][yy]=0;
}
}
int main() {
while(cin >> n >> m) {
memset(vis, 0, sizeof vis);
f = 0;
for(int i = 0; i < n; ++i)
scanf("%s", a[i]);
for(int i = 0; i < n; ++i) {
for(int j = 0; j < m; ++j) {
if(a[i][j] == 'S')
sx = i, sy = j;
if(a[i][j] == 'E')
ex = i, ey = j;
}
}
dfs(sx, sy);
if(f) printf("Yes\n");
else printf("No\n");
}
}
2. bfs(广度优先搜索)
#include <iostream>
#include <cstring>
#include <queue>
using namespace std;
char a[550][550];
int vis[550][550], n, m, sx, sy, ex, ey;
int dir[4][2] = {1, 0, -1, 0, 0, 1, 0, -1};
struct node{
int x, y;
};
int bfs(int x, int y) {
int f = 0;
queue<node> q;
q.push({x, y});
vis[x][y] = 1;
while(!q.empty()) {
node t = q.front(); q.pop();
if(t.x == ex && t.y == ey){
f = 1;break;
}
for(int i = 0; i < 4; ++i){
int xx = t.x + dir[i][0];
int yy = t.y + dir[i][1];
if(a[xx][yy] == 'x' || vis[xx][yy] || xx < 0 || xx >= n || yy < 0 || yy >= m)
continue;
vis[xx][yy] = 1;
q.push({xx, yy});
}
}
return f;
}
int main() {
int t;
cin >> t;
while(t--) {
cin >> n >> m;
memset(vis, 0, sizeof vis);
for(int i = 0; i < n; ++i) {
for(int j = 0; j < m; ++j) {
cin >> a[i][j];
if(a[i][j] == 's'){
sx = i, sy = j;
}
if(a[i][j] == 't'){
ex = i, ey = j;
}
}
}
if(bfs(sx, sy)) cout << "YES" << endl;
else cout << "NO" << endl;
}
}
四、并查集
1. 基本用法
#include<iostream>
using namespace std;
int fa[50500];
int find(int x) {
if(fa[x] == x)
return x;
else
return fa[x]=find(fa[x]);
}
int main() {
int n, m, p, x, y;
scanf("%d%d%d", &n, &m, &p);
for(int i = 1; i <= n; ++i) //初始化每个点
fa[i] = i;
while(m--) {
scanf("%d%d", &x, &y);
fa[find(x)] = find(y);
}
while(p--) {
scanf("%d%d", &x, &y);
if(find(x) == find(y))
printf("Yes\n");
else
printf("No\n");
}
return 0;
}
2. 路径压缩的应用
#include <iostream>
#include <map>
using namespace std;
map<string, string> fa;
map<string, int> weight, ret, sum, ans;
string find(string x){
string y = x;
while(x != fa[x]) x = fa[x];
if(weight[y] > weight[x]){
fa[x] = y;
fa[y] = y;
return y;
}
return x;
}
int main() {
int n, k, x;
cin >> n >> k;
while(n--){
string a, b;
cin >> a >> b >> x;
if(fa[a] == "") fa[a] = a;
if(fa[b] == "") fa[b] = b;
weight[a] += x, weight[b] += x;
if(weight[find(a)] > weight[find(b)])
fa[find(b)] = find(a);
else
fa[find(a)] = find(b);
}
for(auto it = fa.begin(); it != fa.end(); ++it){
ret[find(it->first)]++;
sum[find(it->first)] += weight[it->first];
}
for(auto it = ret.begin(); it != ret.end(); ++it)
if(sum[it->first] / 2 > k && it->second > 2)
ans.insert(*it);
cout << ans.size() << endl;
for(auto it = ans.begin(); it != ans.end(); ++it)
cout << it->first << " " << it->second << endl;
}
五、图论
1. AVL(平衡二叉搜索树)
#include <iostream>
using namespace std;
struct node{
int val;
struct node *left, *right;
};
node *rotateLeft(node *root) {
node *t = root->right;
root->right = t->left;
t->left = root;
return t;
}
node *rotateRight(node *root) {
node *t = root->left;
root->left = t->right;
t->right = root;
return t;
}
node *rotateLeftRight(node *root) {
root->left = rotateLeft(root->left);
return rotateRight(root);
}
node *rotateRightLeft(node *root) {
root->right = rotateRight(root->right);
return rotateLeft(root);
}
int height(node *root) {
if(root == NULL) return 0;
return max(height(root->left), height(root->right)) + 1;
}
node *insert(node *root, int v) {
if(root == NULL) {
root = new node();
root->val = v;
root->left = root->right = NULL;
} else if(v < root->val){
root->left = insert(root->left, v);
if(height(root->left) - height(root->right) > 1)
root = v < root->left->val ? rotateRight(root) : rotateLeftRight(root);
} else{
root->right = insert(root->right, v);
if(height(root->left) - height(root->right) < -1)
root = v > root->right->val ? rotateLeft(root) : rotateRightLeft(root);
}
return root;
}
int main() {
int n, x;
cin >> n;
node *root = NULL;
for(int i = 0; i < n; ++i){
cin >> x;
root = insert(root, x);
}
cout << root->val;
}