准备蓝桥1


根据zq的安排,已经连续两天下午和晚上一直写题,看题了。

递归和递推

先看最简单的
这个链接里面有寒假接触的递归和递推
再有就是侯大佬用斐波那契数列举的例子。
先是递归

#include<iostream>
#include<bits/stdc++.h>
using namespace std;
int main()
{
    int i;
    int a[50]={0};
    a[0] = 1;
    a[1] = 1;
    for(i = 2; i < 15; i ++){
        a[i] = a[i - 1] + a[i - 2];
    }
    for(i = 0; i < 15; i ++)printf("%d ",a[i]);
    return 0;
}

之后再是递归的做法

#include<iostream>
#include<bits/stdc++.h>
using namespace std;
int a[50] = {1,1};

void w(int n)
{
    if(n == 15)return ;
    else{
        a[n] = a[n - 1] + a[n - 2];
    }
    w(n + 1);
}
int main()
{
    w(2);
    for(int i = 0; i < 15; i ++)printf("%d ",a[i]);
    return 0;
}

再下边就是没有人性的acwing
说好是递归跟递推的,(ಥ﹏ಥ)结果我莫名接触了我一点都不会的dfs还有一点点的哈希。难哭我。
在这里插入图片描述

先做92,94,93,717,1208;95写完之后写116,1209最后写
对应蓝书的p11-p16

递归实现指数型枚举

原题链接
先跟上蓝书上的代码

#include<iostream>
#include<bits/stdc++.h>
using namespace std;
int n;
vector<int> chosen;
void calc(int x){
    if (x == n + 1){
        for(int i = 0; i < chosen.size(); i ++)
            printf("%d ",chosen[i]);
        puts("");
        return;
    }
    //“不选x”分支
    calc(x + 1);
    //“选x”分支
    chosen.push_back(x);//在数组的最后添加一个元素
    calc(x + 1);
    chosen.pop_back();//在数组的最后删除一个元素
}
int main()
{
    cin >> n;
    calc(1);
}

走一遍程序,当n=3时,进行calc(1),再进行calc(2),再进行calc(3),再进行calc(4)此时x=4=3+1=n+1,此时的chose为空,输出一个空格,之后就是按照步骤走了。
这可能是我唯一一个看得明白的代码。

递归实现排列型枚举

原题链接
下边先是蓝书的代码

#include<iostream>
#include<bits/stdc++.h>
using namespace std;
int n;
int order[20];
bool chosen[20];
void calc(int k){
    if (k == n + 1){
        for(int i = 1; i <= n; i ++)
            printf("%d ",order[i]);
        puts("");
        return;
    }
    for(int i = 1; i <= n; i ++){
        if(chosen[i])continue;
        order[k] = i;
        chosen[i] = 1;
        calc(k + 1);
        chosen[i] = 0;
        order[k] = 0;
    }
}
int main(){
    cin >> n;
    calc(1);
}

之后是雅文写的代码,当雅文告诉我dfs的时候我的内心是十分抗拒的,拒绝学习超纲内容。

#include <iostream>

using namespace std;
int a[15], book[15];
int n;

void dfs(int u)
{
    if(u == n){
        for(int i = 0; i < n; i ++){
            cout << a[i] << " ";
        }
        cout << endl;
        return ;
    }

    for(int i = 1; i <= n; i ++){
        if(!book[i]){
            book[i] = 1;
            a[u] = i;
            dfs(u + 1);
            a[u] = 0;
            book[i] = 0;
        }
    }

}
int main()
{
    cin >> n;
    dfs(0);
    return 0;
}

再下边就是y总写的代码了

#include<iostream>
#include<vector>
using namespace std;
int n;
vector<int> path;
void dfs(int u,int state)
{
    if(u == n){
        for(auto x : path) cout << x << ' ';
        cout << endl;
        return ;
    }
    for(int i = 0; i < n; i ++){
        if(!(state >> i & 1)){
            path.push_back(i + 1);
            dfs(u + 1,state | (1 << i));
            path.pop_back();
        }
    }
}
int main()
{
    cin >> n;
    dfs(0,0);
    return 0;
}

之后就会有一些相关的知识点
auto声明(自动)
让编译器根据初始值类型直接推断变量的类型,例如:

auto x = 100;//x是int变量
auto y = 1.5;//y是double变量

基于范围的for循环
遍历数组中的每一个元素时使用会比较简单。比如想要输出数组arr中的每一个值,可以用以下方法输出:

int arr[4] = {0,1,2,3};
for(auto i : arr)
cout << i << endl;

关于&和|的知识点
&和|都是二进制的按位操作符
&:二进制“与”(都为1时,结果为1,否则是0),比如1010&1011 = 1010, 1010&1000 = 1000.
|:二进制“或”(有1时,结果为1,都是0时,结果为0),比如1010 | 1011 = 1011,1010 | 1000 = 1010.

递归实现组合型枚举

原题链接
先是蓝书的代码,它的输出是倒过来了,并且因为我的一知半解,我并不知道怎么改这个代码

#include<iostream>
#include<bits/stdc++.h>
using namespace std;
int n,m;
vector<int> chosen;
void calc(int x){
    if (chosen.size() > m || chosen.size() + (n - x + 1) < m){
        return;
    }
    if (x == n + 1){
        for(int i = 0; i < chosen.size(); i ++)
            printf("%d ",chosen[i]);
        puts("");
        return;
    }
    calc(x + 1);
    chosen.push_back(x);
    calc(x + 1);
    chosen.pop_back();
}
int main()
{
    cin >> n >> m;
    calc(1);
}

之后再是一个雅文的代码

#include <iostream>

using namespace std;
int n, m;
int a[105], book[105];
void dfs(int u)
{
    if(u == m){
        for(int i = 0; i < m; i ++){
            cout << a[i] << " ";
        }
        cout << endl;
        return;
    }

    for(int i = 1; i <= n; i ++){
        if(!book[i] && a[u - 1] < i){
            a[u] = i;
            book[i] = 1;
            dfs(u + 1);
            book[i ] = 0;
            a[u] = 0;
        }
    }
}
int main()
{
    cin >> n >> m;
    dfs(0);
    return 0;
}

再跟一个y总的代码

#include<iostream>
#include<cstring>
#include<algorithm>
#include<bits/stdc++.h>
using namespace std;
const int N = 30;
int n,m;
int path[N];
void dfs(int u, int start)
{
    if(u > m)
    {
        for(int i = 1; i <= m; i ++)
            printf("%d ",path[i]);
        puts("");
    }
    else{
        for(int i = start; i <= n; i ++){
            path[u] = i;
            dfs(u + 1, i + 1);
            path[u] = 0;
        }
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    dfs(1,1);
    return 0;
}

其实代码的思路都是好懂的,但是当你自己写的时候,你不一定能有思路就是了。

二分与前缀和

做题顺序789、790、795、796、730、1227、1230、99、1221
1221(暴力或二分或哈希)

二分

789、790、730、1227(二分)
先写上寒假二分的点
蓝书上二分对应了p25,虽然没有看太明白它说的一些点,但是学到了几个函数
lower_bound(起始地址,结束地址,要查找的数值)返回的是数值第一个出现的位置
upper_bound(起始地址,结束地址,要查找的数值)返回的是第一个大于待查找数值出现的位置
binary_search(起始地址,结束地址,要查找的数值)返回的是是否存在这么一个数,是一个bool值
蓝书上写
s.lower_bound(x)查找>=x的元素中最小的一个,并返回指向该元素的迭代器。
s.upper_bound(x)查找>x的元素中最小的一个,并返回指向该元素的迭代器。

数的范围

原题链接
之后就是我写的代码了,思路什么的都很简单,但是zq说也要学会手写二分

#include<bits/stdc++.h>
#include<iostream>
#include<algorithm>
//#include<vector>
using namespace std;
int main()
{
    int n,q,l,r;
    scanf("%d%d",&n,&q);
    int a[n+10]={0};
    for(int i = 0; i < n; i ++){
        scanf("%d",&a[i]);
    }
    for(int i = 0; i < q; i ++){
        int b;
        scanf("%d",&b);
        if(binary_search(a ,a + n, b)){
            printf("%d %d\n",lower_bound(a ,a + n, b)-a,upper_bound(a ,a + n, b)-a-1);
        }
        else
            printf("-1 -1\n");
        b = 0;
    }
    return 0;
}

之后就有了手写二分

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int n,q,x,a[10010];
    scanf("%d%d",&n,&q);
    for(int i = 0; i < n; i ++)scanf("%d",&a[i]);
    while(q--){
        scanf("%d",&x);
        int l = 0, r = n - 1;
        while(l < r){
            int mid = l + r >> 1;
            if(a[mid] < x) l = mid + 1;
            else
                r = mid;
        }
        if(a[l] != x){
            printf("-1 -1\n");
            continue;
        }
        int l1 = l, r1 = n;
        while(l1 + 1 < r1){
            int mid = l1 + r1 >> 1;
            if(a[mid] <= x) l1 = mid;
            else
                r1 = mid;
        }
        printf("%d %d\n",l,l1);
    }
    return 0;
}

之后的例题再去acwing找吧,思路差不都都是那个思路

前缀和

对应蓝书的p21,虽然蓝书的题解不是很平易近人
下面跟一个比较友善的讲解什么是前缀和
链接

前缀和(一维前缀和)

原题链接

#include<bits/stdc++.h>
#include<iostream>
#include<algorithm>
using namespace std;
int main()
{
    int n,m;
    cin >> n >> m;
    int a[n+10]={0},b[n+10]={0};
    for(int i = 1; i <= n; i ++){
        cin >> a[i];
        b[i] = b[i - 1] + a[i];
    }
    for(int i = 0; i < m; i ++){
        int x,y;
        cin >> x >> y;
        printf("%d\n",b[y]-b[x-1]);
    }
    return 0;
}

子矩阵的和(二维前缀和)

原题链接
友善题解
一开始是不太清楚要怎么计算二维的前缀和的,看了题解之后清晰了不少,所以鄙人代码和题解的基本一样

#include<bits/stdc++.h>
#include<iostream>
#include<algorithm>
using namespace std;

const int N = 1010;
int a[N+10][N+10],b[N+10][N+10];
int main()
{
    int n,m,q;
    cin >> n >> m >> q;
    for(int i = 1; i <= n; i ++){
        for(int j = 1; j <= m; j ++){
            scanf("%d",&a[i][j]);
            b[i][j] = b[i-1][j] + b[i][j-1] + a[i][j] - b[i - 1][j - 1];
        }
    }
    for(int i = 0; i < q; i ++){
        int x1,y1,x2,y2;
        cin >> x1 >> y1 >> x2 >> y2;
        printf("%d\n",b[x2][y2]-b[x2][y1-1]-b[x1-1][y2]+b[x1-1][y1-1]);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值