【AcWing】蓝桥杯C++ AB组辅导课

教学计划与递归


如何准备蓝桥杯比赛

  • 要有一定刷题量
    若想在省赛中取得较好成绩,建议做200题左右。
    若想在国赛中取得较好成绩,建议做300题左右。
    本课程约讲解100题左右。

  • 要重视调试
    有思路得前提下,若调试不过,不要立马问别人。要自己努力解决问题。

  • 要重视考试。
    感受真实氛围,检验学习成果。

  • 比赛时比的并不是去发明或者去创造某一个思路,比赛比的是熟练度。

做题的套路

  • 算法题特点:
    1、与数学、物理等学科相比,算法题的模型相对较少。
    2、思维量高
    3、编写编程能力 。要用理论去指导实践。数学题想出来就能做出来,但是算法题能想出来不一定能实现出来。

  • 做题过程
    1、看题目描述
    2、分析,抽象出来它考什么模型。分析出题人是想问什么。
    3、回忆之前学过的算法或做过的题目能不能解决这个问题。若不能,再去回溯。解决方案是平时多去积累一些题目,多去刷一些题目。只有平时积累的多了,考试的时候才能学以致用。

  • 如何判断一个算法能不能用?
    1、首先看正确性
    2、再看时间是否超限制。
    C++ 评测机一秒约运行一亿次。若算法的的时间复杂度超过108,则可能会超时。
    在这里插入图片描述
    做题时,先看数据范围,排除不能使用的算法。找到题目数据范围区间之内的算法。这样做题思路会更明确。
    数据范围可以带给我们非常多的信息。

  • 学算法一定要落实到代码上

  • 若输入输出 范围 小于 105 推荐用 cin / cout 否则用 scanf / printf 输入时间会快一倍左右。

第一讲 递归与递推

  • 递归是什么?递归就是自己调用自己。

递归计算斐波那契数列

#include<iostream>

using namespace std;

int f(int n )
{
   
    if (n == 1) return 1;
    if (n == 2) return 2;
    return f(n - 1) + f(n - 2); 
}
int main()
{
   
    int n ; 
    cin >> n;

    cout << f(n);
    
    return 0;
}
  • 如何分析判断 递归执行顺序
    所有递归都可以转化为一颗递归搜索树
    在这里插入图片描述
  • 记忆几个比较常用的数据
    21 = 2
    22 = 4
    23 = 8
    24 = 16
    25 = 32
    26 = 64
    27 = 128
    28 = 256
    29 = 512
    210 = 1024
    215 = 32768
    216 = 65536
    220 约等于106
    263 约等于 108

递归实现指数型枚举

在这里插入图片描述

#include<iostream>
#include<cstring>
#include<iostream>
#include<algorithm>

using namespace std;

const int N = 16;

int n;
int st[N];//状态,记录每个位置当前的状态:0表示还没考虑,1表示选它,2表示不选它。

void dfs(int u)
{
   
    if (u > n)
    {
   
        for (int i =1; i <= n; i ++ )
            if (st[i] == 1)
                printf("%d ", i);
        printf("\n");
        return;
    }

    st[u] = 2;
    dfs(u + 1);    //第一个分支: 不选
    st[u] = 0;	   //恢复现场

    st[u] = 1;
    dfs(u + 1);   // 第二个分支: 选
    st[u] = 0;	
}

int main()
{
   
    cin >> n;

    dfs(1);

    return 0;
}

变形 :如何输出所有方案?

#include<iostream>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>

using namespace std;

const int N = 16;

int n;
int st[N];//状态,记录每个位置当前的状态:0表示还没考虑,1表示选它,2表示不选它。
vector<vector<int>> ways;

void dfs(int u)
{
   
    if (u > n)
    {
   
    	vector<int> way;
        for (int i = 1; i <= n; i ++ ) // 记录方案
            if (st[i] == 1)
                way.push_back(i);
         ways.push_back(way);
        return;
    }

    st[u] = 2;
    dfs(u + 1);    //第一个分支: 不选
    st[u] = 0;	   //恢复现场

    st[u] = 1;
    dfs(u + 1);   // 第二个分支: 选
    st[u] = 0;	
}

int main()
{
   
    cin >> n;

    dfs(1);

	for (int i = 0; i < ways.size(); i ++ )
	{
   
		for (int j = 0; j < ways[i].size(); j ++) printf("%d ", ways[i][j]);
		puts(""); // puts是输出一个字符串,但是这个字符串为空,仅有一个回车。
		//相当于printf("\n"); puts("")等价于只输出回车。
	}
	
    return 0;
}

递归实现排列型枚举

  • 有两种顺序
    1、依次枚举每个数放到每个位置
    2、依次枚举每个位置放哪个数
    在这里插入图片描述
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>

using namespace std;

const int N = 10;

int n;
int state[N];  // 0表示还没放数,1~n表示放了哪个数
bool used[N];  // true表示用过,false表示还未用过

void dfs(int u)
{
   
    if (u > n)
    {
   
        for (int i = 1; i <= n; i ++ ) 
        	cout << state[i] << ' ';
        cout << endl;
        return;
    }

    for (int i = 1; i <= n; i ++)
        if (!used[i])
        {
   
            state[u] = i;
            used[i] = true;
            dfs(u + 1);
            state[u] = 0;
            used[i] = false;
        }
}

int main()
{
   
    cin >> n;

    dfs(1);

    return 0;
}

递归实现组合型枚举

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>

using namespace std;

const int N = 30;

int n, m;
int way[N];

void dfs(int u, int start)
{
   
	if (n + u - start < m) return; // 如果把后面所以的数都选上还不够m个 当前分支无解。
    if (u == m + 1)
    {
   
        for (int i = 1; i <= m ; i ++) printf("%d ", way[i]);
        puts("");
        return;
    }

    for (int i = start; i <= n; i ++)
    {
   
        way[u] = i;
        dfs(u + 1, i + 1);
        way[u] = 0;
    }
}

int main()
{
   
    scanf("%d%d", &n, &m);

    dfs(1, 1);

    return 0;
}

AcWing116.飞行员兄弟

第二讲 二分与前缀和

AcWing789.数的范围

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>

using namespace std;

const int N = 100010;

int n ,m;
int q[N];

int main()
{
   
    cin >> n >> m;
    for (int i = 0; i < n; i ++) cin >> q[i];

    for (int i = 0; i < m; i ++)
    {
   
        int x;
        cin >> x;
        int l = 0, r = n - 1;
        while (l < r)
        {
   
            int mid = l + r >> 1;
            if (q[mid] >= x) r = mid;
            else l = mid + 1;
        }

        if (q[r] == x) //  比较的是数组里的元素
        {
   
            cout << r << ' ';
            r = n - 1;
            while (l < r)
            {
   
                int mid = l + r + 1 >> 1;
                if (q[mid] <= x) l = mid; //**这里写mid是不对的,要写[mid]
                else r = mid - 1;
            }
            cout << l << endl;
        }
        else cout << "-1 -1" << endl;
    }

    return 0;
}

AcWing790.数的三次方根

#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

int main()
{
   
    double x;
    cin >> x;
    double l = -100000, r = 100000;
    while (r - l > 1e-8)
    {
   
        double mid = (l + r) / 2;
        if (mid * mid * mid >= x) r = mid;
        else l = mid;
    }

    printf("%.6lf", l);

    return 0;
}

在这里插入图片描述

AcWing795.前缀和

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int N = 100010;

int n, m;
int a[N];
int s[N];

int main()
{
   
    cin >> n >> m;
    
    for (int i = 1; i <= n; i ++)
    {
   
        cin >> a[i];
        s[i] = s[i - 1] + a[i];
    }

    while (m --)
    {
   
        int l, r;
        cin >> l >> r;
        cout << s[r] - s[l - 1] << endl;        
    }
    
    return 0;
}

在这里插入图片描述

AcWing796.子矩阵的和

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 1010;

int n, m, q;
int a[N][N], s[N][N];

int main()
{
   
    cin >> n >> m >> q;

    for (int i = 1; i <= n; i ++)
        for (int j = 1; j <= m; j ++)
        {
   
            cin >> a[i][j];
            s[i][j] = s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1] + a[i][j];//++-+
        }
    
    while (q --)
    {
   
        int x1, y1, x2, y2;
        cin >> x1 >> y1 >> x2 >> y2;
        cout << s[x2][y2] - s[x1 - 1][y2] - s[x2][y1 - 1] + s[x1 - 1][y1 - 1] << endl;//+--+
    }

    return 0;
}
#include <iostream>

using namespace std;

const int N = 10010;

int n, m, q;
int a[N][N];
int s[N][N];

int main()
{
   
    cin >> n >> m >> q;
    for (int i = 1; i <= n ; i++)
        for (int j = 1; j <= m; j ++)
        {
   
            cin >> a[i][j];
            s[i][j] = s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1] + a[i
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值