蓝桥杯Acwing知识点总结

数学

如果 a,b 均是正整数且互质,那么由 ax+by,x≥0,y≥0 不能凑出的最大数是 (a−1)(b−1)−1。

c++中,a/b 的结果默认下取整,使用 ceil() 可以获得上取整,但是要记得类型转换将 double 转为 int
或者,用(a+b-1)/b 下取整的结果表示 a/b 的上取整

一维数组转二维数组 x/3 和 x%3

动态规划

01 背包问题

01 表示使用 1 次或者使用 0 次
image.png
DP分析法

  • 状态表示 f[i][j]
    • 集合:所有数量为 i ,总体积不超通过 j 的物品的选法集合
    • 属性:最大价值
  • 状态计算
    • 所有不选择第 i 个物品方案中的最大值 f[i-1][j]
    • 所有选择第 i 个物品方案中的最大值 f[i-1][j-v[i]]+w[i]

朴素代码

#include<bits/stdc++.h>
using namespace std;
const int N = 1010;
int n,m;
int w[N],v[N];
int f[N][N];
int main(){
    
    
    cin>>n>>m;
    for(int i=1;i<=n;i++) cin>>v[i]>>w[i];
    for(int i=1;i<=n;i++){
    
    
        for(int j=0;j<=m;j++){
    
    
            f[i][j] = f[i-1][j];
            if(j>=v[i]) f[i][j] = max(f[i][j],f[i-1][j-v[i]]+w[i]);
        }
    }
    cout<<f[n][m];
    return 0;
}

优化空间后代码

#include<bits/stdc++.h>
using namespace std;
const int N = 1010;
int n,m;
int w[N],v[N];
int f[N];
int main(){
    
    
    cin>>n>>m;
    for(int i=1;i<=n;i++) cin>>v[i]>>w[i];
    for(int i=1;i<=n;i++){
    
    
        for(int j=m;j>=v[i];j--){
    
    
            f[j] = max(f[j],f[j-v[i]]+w[i]);
        }
    }
    cout<<f[m];
    return 0;
}

优化思路

由于j是从大到小循环的,假设j = 5; j >= 2; j –; 也就是这一层(第i层)会先算出来f[5],(注意这个时候,第i层正在算f[5], 也就是说第i层没有更新f[4] f[3],也就是此时的f[4] f[3] 是i - 1层的)那么算f[5]要用到比他更小的f[4]或者f[3]也就是i - 1层的了。

最长上升子序列

image.png
分析:

  • 状态表示 f[i]
    • 集合:所有以a[i] 结尾的严格单调上升子序列
    • 属性:Max/Min/数量
  • 状态计算

image.png

枚举模拟排序

善用sscanf()函数
格式化读入数据 sscanf(a,b,c)是把a中的每个字符,按照b格式,赋值给c
例如

将 字符串s"03:08:20" 赋值给 int 类型的hour minue time
sscanf(s.c_str(),"%d:%d:%d",&hour,&minute,&time)

相对的,sprintf(a,b,c) 把c中的字符,按照b格式,赋值给a

sprintf(format_time,"%02d:%02d:%02d", day, hour, minute); //反向打印到format_time中

结构体vector

// 定义结构体
struct ord_struct{
    
    
    int ts,id;
    bool operator<(const ord_struct& t)const{
    
    
        return ts<t.ts;
    }
};
// 定义vector
vector<ord_struct> ord;
// 遍历
for(int i=0;i<ord.size();i++){
    
    
        cout<<ord[i].ts<<endl;
    }

pair

#define x first
#define y second
typedef pair<int,int> PII;

树状数组与线段树

树状数组

树状数组,顾名思义就是把数组用树的形式表示出来,它有如下特点

  • 在O(logn)下对根据原数组构造出的树中节点值加任何数字
  • 在O(logn)下求原数组前缀和

具体表示
image.png

  • 构造出的树也是用数组表示,tr[]
  • tr[x]的层数k = x的二进制表示最后有几个零就在第几层
  • tr[x]的值表示从 (x-2^k, x] 累加,2^k 为 lowbit(x) 即x&-x,lowbit(x) 为 x 的父节点
  • 所以,tr[x]的值表示(x-lowbit(x),x] 累加

在O(logn)下对根据原数组构造出的树中节点值加任何数字

void add(int x, int v)
{
    
    
    for (int i = x; i <= n; i += lowbit(i)) tr[i] += v;
}

在O(logn)下求原数组前缀和

int query(int x)
{
    
    
    int res = 0;
    for (int i = x; i; i -= lowbit(i)) res += tr[i];
    return res;
}

image.png

#include<bits/stdc++.h>
using namespace std;
const int N = 100010;
int n,m;
int tr[N],arr[N];
int lowbit(int x){
    
    
    return x & -x;
}
void add(int x,int v){
    
    
    for(int i = x;i<=n;i+=lowbit(i)){
    
    
        tr[i]+=v;
    }
}
int query(int x){
    
    
    int res = 0;
    for(int i = x;i;i-=lowbit(i)){
    
    
        res+=tr[i];
    }
    return res;
}
int main(){
    
    
    cin>>n>>m;
    for(int i=1;i<=n;i++){
    
    
        cin>>arr[i];
    }
    for (int i = 1; i <= n; i ++ ) add(i, arr[i]);
    while(m--){
    
    
        int k,a,b;
        cin>>k>>a>>b;
        if(k==1) add(a,b);
        else cout<<query(b)-query(a-1)<<endl;
    }
    return 0;
}

线段树

太复杂了没看。。回头补上

双指针、bfs

双指针

虽然叫双指针,但是和指针没有关系。
双指针可以想象成,数组中有两个表示位置的变量,不断更改划分的范围
常常用来优化代码,将O(n^2)简化为O(n)

// 原本
for(int i = 0; i < n; i ++ ){
    
    
    for(int j = 0; j < m; j ++ ){
    
    
    }
}
// 现在
for(int i = 0, j = 0; i < n; i ++ ){
    
    
    if(check(j)) j++; // 如果j满足某些条件
}

bfs

  • bfs 对应队列 先进先出的思想 可以找到通向某一节点的最短路径
  • dfs 对应栈 先进后出的思想 递归

image.png
bfs遍历顺序:1 2 3 4 5 6 7
我们用 队列 来进行bfs操作:
先把根节点入队
while(存在其他节点没入队 即 队列不空){
把队头关联点入队
对头出队
}

判重数组 st[] 入队时判重
while(queue非空){
    
    
  t <- 队头
  for(扩展t){
    
    
      var = 新节点
      if(!st[var]){
    
    
         var -> 队尾 
      }
  }
}

image.png

#include <bits/stdc++.h>
#define x first
#define y second
using namespace std;
const int N = 210;
typedef pair<int, int> PII;
int T;
int R, C;
char g[N][N];
int dist[N][N];

int bfs(PII start,PII end){
    
    
    queue<PII> que;
    que.push(start);
    memset(dist, -1, sizeof dist);
    dist[start.x][start.y] = 0;
    int dx[4] = {
    
    0, 1, 0, -1},dy[4] = {
    
    1, 0, -1 ,0};
    while(que.size()){
    
    
        auto t = que.front();
        que.pop();
        for(int i = 0; i < 4; i ++ ){
    
    
            int x = t.x + dx[i],y = t.y + dy[i];
            if(x < 0 || x >= R || y < 0 || y >= C) continue; // 出界
            if(g[x][y] == '#') continue; // 遇到障碍物
            if(dist[x][y] != -1) continue; // 走过了

            dist[x][y] = dist[t.x][t.y] + 1;
            if (end == make_pair(x, y)) return dist[x][y];
            que.push({
    
    x,y});
        }
    }
    return -1;
}
int main(){
    
    
    cin >> T;
    while(T -- ){
    
    
        cin >> R >> C;
        for(int i = 0; i < R; i ++ ) scanf("%s", g[i]);
        PII start, end;
        for(int i = 0; i < R; i ++ )
         for(int j = 0; j < C; j ++){
    
    
             if(g[i][j] == 'S') start = {
    
    i, j};
             if(g[i][j] == 'E') end = {
    
    i, j};
         }
    int distance = bfs(start, end);
    if(distance==-1) puts("oop!");
    else cout<<distance<<endl;
    }
    return 0;
}

连通块问题

  • bfs 或 dfs
  • 并查集

image.png

#include <bits/stdc++.h>
#define x first
#define y second
using namespace std;
typedef pair<int, int> PII;
const int N = 1010;
int n;
int cnt;
PII q[N*N];
char g[N][N];
bool st[N][N];
int dx[4] = {
    
    -1, 0, 1, 0},dy[4] = {
    
    0, 1, 0, -1};

void bfs(int i, int j, int &total, int &bound){
    
    
    int hh = 0, tt = 0;
    q[0] = {
    
    i, j};
    while(hh <= tt){
    
    
        total ++;
        auto t = q[hh ++];
        bool flag = false;
        for(int i = 0; i < 4; i ++ ){
    
    
            int x = t.x + dx[i], y = t.y + dy[i];
            if(x < 0 || x >= n || y < 0 || y >= n) continue;
            if(st[x][y]) continue;
            if(g[x][y] == '.'){
    
    
                flag = true;
                continue;
            }
            st[x][y] = true;
            q[++tt] = {
    
    x, y};
        }
        if(flag) bound ++;
        
    }
}
int main(){
    
    
    cin >> n;
    for(int i = 0; i < n; i ++ ) scanf("%s",g[i]);
    for(int i = 0; i < n; i ++ ){
    
    
        for(int j = 0; j < n; j ++ ){
    
    
            if(st[i][j] == false && g[i][j] == '#'){
    
    
                st[i][j] == true;
                int total = 0, bound = 0;
                bfs(i, j, total, bound);
                if(total == bound){
    
    
                    cnt ++;
                }
            }
        }
    }
    cout << cnt;
    return 0;
}

图论

如何存图

  • 邻接矩阵 ( 适合于稀疏图)
  • 邻接表
    • vector
    • 数组模拟单链表

求图中最长的一段距离(树的直径问题)

  1. 图中随便找一个点,找到距离这个点最远的点
  2. 对于上一步最远的点,在图中找到距离这个点最远的点,这两点之间的距离即为树的直径

反证法证明

y 为距离 x 最远的点,u v是树的直径,假设y不是任何一条直径上的端点
image.png
有交点:因为 y 是距离x最远的点,所以xy>=xa+av 即 ay >= av,两边同时加au,得到ay+au >= uv,所以y必定在直径的端点上,与假设矛盾
无交点:因为 y 是距离x最远的点,所以xy>=ya+ab+bu => ax>=ub,xy>=xa+ab+bv **=> **ay>= bv,所以y必定在直径的端点上,与假设矛盾

大臣的旅费
image.png

#include <bits/stdc++.h>
using namespace std;
const int N = 100010;
int n;
int dist[N];
struct Edge{
    
    
    int id, w;
};
vector<Edge> h[N];

void dfs(int u, int father, int distance){
    
    
    dist[u] = distance;
    for(auto node: h[u]){
    
    
        if(node.id != father) dfs(node.id, u, distance + node.w);
    }
}
int main(){
    
    
    cin >> n;
    int p, q, d;
    while(cin >> p >> q >> d){
    
    
        h[p].push_back({
    
    q, d});
        h[q].push_back({
    
    p, d});
    }
    dfs(1, -1, 0);
    int u = 1;
    for(int i = 1; i <= n; i ++ ){
    
    
        if(dist[i] > dist[u]){
    
    
            u = i;
        }
    }
    dfs(u, -1, 0);
    for(int i = 1; i <= n; i ++ ){
    
    
        if(dist[i] > dist[u]){
    
    
            u = i;
        }
    }
    int s = dist[u];
    printf("%lld",s*10 + s+s*(s-1ll)/2);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_45660485/article/details/124095820
今日推荐