一. 二分
在某个单调区间内可以logn时间复杂度查找出某个符合条件的数
模板1.如果在某个区间范围内没有val,那么就找大于等于val数,有就是区间左侧的数
int search(int a[], int l, int r, int val) { //存在val为区间左侧的数 ,不存在则为大于val值的
while (l < r) {
int mid = (l + r) >> 1; //右移比除以2快
if (a[mid] >= val) r = mid;
else l = mid + 1;
}return l;
}
模板2.如果在某个区间范围内没有val,那么就找小于等于val数,有就是区间右侧的数
int search1(int a[], int l, int r, int val) { //存在val为区间右侧,不存在则为小于val值的
while (l < r) {
int mid = (l + r + 1) >> 1;
if (a[mid] <= val) l = mid;
else r = mid - 1;
}
return l;
}
模板1,2所得的 l下标均不会超出数组下标的范围
lower_bound:查找第一个大于等于val的数
upper_bound:查找第一个大于val的数
二. 差分
1.差分数组: b[i] = a[i] - a[i - 1]
2.给a数组中的[ l, r]区间中的每一个数都加上c,只需对差分数组b做 b[l] + = c, b[r+1] - = c。时间复杂度为O(1), 大大提高了效率。
3. 然后通过a[i] = b[i] + a[i - 1],得到原数组
三. 二维前缀和
1.前缀和数组:pre[i][j] = pre[i - 1][j] + pre[i][j - 1] - pre[i - 1][j - 1] + a[i][j];
2.求区域[x1,x2] [y1,y2]内的和:pre[x2][y2] - pre[x2][y1 - 1] - pre[x1 - 1][y2] + pre[x1 - 1][y1 - 1]
3.如果是求(r * r)区域
pre[x2][y2] - pre[x2][y2 - r] - pre[x2 - r][y2] + pre[x2 - r][y2 - r]
四. 并查集
图论的连通性,判断点是否在同一个集合,子代父代,主要就是 合并(merge), 查(find), 集合
模板
#include<bits/stdc++.h>
using namespace std;
const int N = 100000+10;
int p[N],st[N], n,m;
//找祖先
int find(int x) {
if (p[x] != x) {
p[x] = find(p[x]);
}
return p[x];
}
//并,合并为一个祖先
void merge(int x, int y){
if (find(x) != find(y)) {
p[find(x)] = find(y);
}
}
int main() {
cin >> n >> m;
//初始化,让自己是自己的祖先
for (int i = 1; i <= n; i++) {
p[i] = i;
}
while(m--) {
char c;
int a, b;
cin >> c >> a >> b;
if (c == 'M') {
merge(a, b);
}else {
int x = find(a), y = find(b);
if (x == y) cout << "Yes" << "\n";
else cout << "No" << "\n";
}
}
return 0;
}
五.dfs bfs
dfs模板类
一般会用到 st 数组去重,或者哈希表去重
回溯都是针对它的子节点来说
拓展方式:它可以变成什么情况的
void dfs()//参数用来表示状态
{
if(到达终点状态)
{
...//根据题意添加
return;
}
if(越界或者是不合法状态)
return;
if(特殊状态)//剪枝
return ;
for(扩展方式)
{
if(扩展方式所达到状态合法)
{
修改操作;//根据题意来添加
标记;
dfs();
(还原标记);
//是否还原标记根据题意
//如果加上(还原标记)就是 回溯法
}
}
}
AcWing 1209. 带分数(蓝桥杯辅导课) - AcWing
bfs
BFS()
{
queue<int> q;//初始化队列Q
while(!q.empty()) //队列不为空
{
if() //判断是否找到了目标
{
}
//队首出队
for()
{
//依旧是四个方向
//符合条件的入队
//标记入队的点
}
}
}
六.Floyd
找最短路,通常在图问题,最小环
找最短路模板
#include<bits/stdc++.h>
using namespace std;
int n, m, k;
const int N = 210;
int edges[N][N];
void floyd() { //floyd找最短路
for (int k = 1; k <= n; k++) {
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
if(edges[i][k] != INT_MAX && edges[k][j] != INT_MAX) {
edges[i][j] = min(edges[i][j], edges[i][k] + edges[k][j]);
}
}
}
}
}
int main() {
ios_base::sync_with_stdio(0);
cin.tie(0);
cin >> n >> m >> k;
//初始化建图
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
if(i == j) edges[i][j] = 0;
else edges[i][j] = INT_MAX;
}
}
while(m--) {
int x, y, z;cin>>x >> y >> z;
edges[x][y] = min(edges[x][y], z);
}
floyd();
while(k--) {
int x, y;
cin >> x >> y;
if (edges[x][y] == INT_MAX) cout << "impossible" << "\n";
else cout << edges[x][y] << "\n";
}
return 0;
}
dijkstra
#include <bits/stdc++.h>
using namespace std;
typedef pair<int, int> PII;
const int N = 150000;
int h[N], e[N], w[N], idx,ne[N], dist[N];
bool st[N];
int n, m;
void add(int a, int b, int c)
{
e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
}
int dijkstra()
{
memset(dist, 0x3f, sizeof dist);
dist[1] = 0;
priority_queue<PII, vector<PII>, greater<PII>> q;
q.push({0, 1});
while (q.size())
{
auto it = q.top();
q.pop();
int ver = it.second, distance = it.first;
if (st[ver]) continue;
st[ver] = 1;
for (int i = h[ver]; i != -1; i = ne[i])
{
int j = e[i];
if (dist[j] > distance + w[i])
{
dist[j] = distance + w[i];
q.push({dist[j], j});
}
}
}
return dist[n];
}
int main()
{
cin >> n >> m;
memset(h, -1, sizeof h);
while (m -- )
{
int a, b, c;
cin >> a >> b >> c;
add(a, b, c);
}
int q = dijkstra();
if (q == 0x3f3f3f3f) cout << -1;
else cout << q;
return 0;
}
最小环
(302条消息) 最小环(有向图,无向图)_未央吖的博客-CSDN博客
七.质数
0,1是合数
1.试除法
bool isprime(int n) {
if (n < 2) return true;
for (int i = 2; i <= n / i; i++) {
if (n % i == 0) return true;
}
return false;
}
2.埃式筛法
void isprime() {
st[1] = true;
int cnt = 0;
for (int i = 2; i <= N; i++) {
if(!st[i]) {
a[cnt++] = i;
for (int j = i * 2; j <= N; j += i) st[j] = true;
}
}
}
八.约数
1.
2.约数个数
3.约数之和
九.背包问题
1. 0 1背包 每个物品只可以取一次
#include<bits/stdc++.h>
using namespace std;
const int N = 1010;
int v[N],w[N], n, V, dp[N];
int main()
{
cin >> n >> V;
for (int i = 1; i <= n; i++) cin >>v[i] >> w[i];
for (int i = 1; i <= n; i++) {
for (int j = V; j >= v[i]; j--)
dp[j] = max(dp[j], dp[j - v[i]] + w[i]);
}
cout << dp[V];
return 0;
}
2.完全背包 每个物品可以任意取
#include<bits/stdc++.h>
using namespace std;
const int N = 1010;
int v[N],w[N], n, V, dp[N];
int main()
{
cin >> n >> V;
for (int i = 1; i <= n; i++) cin >>v[i] >> w[i];
for (int i = 1; i <= n; i++) {
for (int j = v[i]; j <= V; j++)
dp[j] = max(dp[j], dp[j - v[i]] + w[i]);
}
cout << dp[V];
return 0;
}
3.多重背包 每个物品取s[i]次
#include<bits/stdc++.h>
using namespace std;
const int N = 1010;
int v[N],w[N],s[N], n, V, dp[N][N];
int main()
{
cin >> n >> V;
for (int i = 1; i <= n; i++) cin >>v[i] >> w[i]>>s[i];
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= V; j++) {
for (int k = 0; k*v[i] <= j && k <= s[i];k++) {
dp[i][j] = max(dp[i][j], dp[i - 1][j - k*v[i]] + k * w[i]);
}
}
}
cout << dp[n][V];
return 0;
}
十.线性dp
十 一.进制转换
1. 10进制转为n进制
#include<bits/stdc++.h>
using namespace std;
string sums(int n, int c) {
string s;
while(n) {
s += to_string(n % c);
n /= c;
}
reverse(s.begin(),s.end());
return s;
}
int main() {
//将16从10进制转为7进制
string s = sums(16, 7);
cout << s;
return 0;
}
2.n进制转为10进制
#include<bits/stdc++.h>
using namespace std;
#define x first
#define y second
typedef long long ll;
const int N = 1010;
int sums(string s, int x) {
reverse(s.begin(), s.end());
int sum = 0, cnt = 1;
for (int i = 0; i < s.size(); i++) {
sum += cnt * (s[i] - '0');
cnt *= x;
}
return sum;
}
int main() {
//将s从2进制转为10进制
string s = "1101";
int m = sums(s, 2);
cout << m;
return 0;
}
十二.日期类
#include<bits/stdc++.h>
using namespace std;
#define x first
#define y second
typedef long long ll;
const int N = 1010;
int month1[] = {0,31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
int month2[] = {0,31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
int main() {
//将s从2进制转为10进制
for (int year = 2000; year <= 2019; year++) {
for (int month = 1; month <= 12; month++) {
//4年一闰,百年不闰,400年又一闰
if ((year%4 == 0 && year % 100) || (year % 400 == 0)) {
for (int day = 1; day <= month2[month]; day++) {
}
}else{
}
}
}
return 0;
}
十三.注意点
1.这样会加速很多
使用"\n",不要使用endl使用ios_base::sync_with_stdio(0);
cin.tie(0);2.0x3f3f3f3f大约10^9,而INT_MAX小于 2 * 10^e9
3.蓝桥杯国赛后4个暴力(不用看什么算法了,基本不会),先从大题做,填空题之后再思考
4.-std=c++11