蓝桥杯^^专题

一. 二分

在某个单调区间内可以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],得到原数组 

3729. 改变数组元素 - AcWing题库

三. 二维前缀和

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]

796. 子矩阵的和 - AcWing题库

四. 并查集

图论的连通性,判断点是否在同一个集合,子代父代,主要就是 合并(merge), 查(find), 集合

模板

836. 合并集合 - AcWing题库

#include

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;
}

837. 连通块中点的数量 - AcWing题库

五.dfs bfs

dfs模板类

一般会用到 st 数组去重,或者哈希表去重

回溯都是针对它的子节点来说

拓展方式:它可以变成什么情况的

void dfs()//参数用来表示状态  
{  
    if(到达终点状态)  
    {  
        ...//根据题意添加  
        return;  
    }  
    if(越界或者是不合法状态)  
        return;  
    if(特殊状态)//剪枝
        return ;
    for(扩展方式)  
    {  
        if(扩展方式所达到状态合法)  
        {  
            修改操作;//根据题意来添加  
            标记;  
            dfs();  
            (还原标记);  
            //是否还原标记根据题意  
            //如果加上(还原标记)就是 回溯法  
        }  
 
    }  
}  

AcWing 1209. 带分数(蓝桥杯辅导课) - AcWing

bfs

BFS()
{
       queue q;//初始化队列Q 
       while(!q.empty())  //队列不为空
       {
               if() //判断是否找到了目标
               {

               }
               //队首出队
               for()
               {
                       //依旧是四个方向
                       //符合条件的入队
                       //标记入队的点
               }
       }
}

六.Floyd

找最短路,通常在图问题,最小环

找最短路模板

854. Floyd求最短路 - AcWing题库

#include

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;
}

4074. 铁路与公路 - AcWing题库

最小环

(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;
        }
    }
}

868. 筛质数 - AcWing题库

867. 分解质因数 - AcWing题库

八.约数

1.

869. 试除法求约数 - AcWing题库

2.约数个数

870. 约数个数 - AcWing题库

3.约数之和

871. 约数之和 - AcWing题库

九.背包问题 

1. 0 1背包        每个物品只可以取一次

2. 01背包问题 - AcWing题库

#include

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.完全背包        每个物品可以任意取

3. 完全背包问题 - AcWing题库

#include

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]次

4. 多重背包问题 I - AcWing题库

#include

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.895. 最长上升子序列 - AcWing题库

2.896. 最长上升子序列 II - AcWing题库

3.897. 最长公共子序列 - AcWing题库 

4.902. 最短编辑距离 - AcWing题库

5.899. 编辑距离 - AcWing题库 

十 一.进制转换 

1. 10进制转为n进制

#include
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

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

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;
}

你可能感兴趣的:(2023蓝桥杯,蓝桥杯,c++,算法)