2021年4月 第十二届蓝桥杯软件类省赛C++B组第一场 真题题解

文章目录

  • 题目结构
  • 填空题
    • 第一题 空间
    • 第二题 卡片
    • 第三题 直线
    • 第四题 货物摆放
    • 第五题 路径
  • 程序题
    • 第六题 时间显示
    • 第七题 砝码称重
    • 第八题 杨辉三角形
    • 第九题 双向排序
    • 第十题 括号序列
  • 总结

题目结构

题目 类型 分值
第一题 结果填空 5分
第二题 结果填空 5分
第三题 结果填空 10分
第四题 结果填空 10分
第五题 结果填空 15分
第六题 程序设计 15分
第七题 程序设计 20分
第八题 程序设计 20分
第九题 程序设计 25分
第十题 程序设计 25分

填空题

第一题 空间

  • 问题描述

    小蓝准备用 256 M B 256MB 256MB 的内存空间开一个数组,数组的每个元素都是 32 32 32 位二进制整数,如果不考虑程序占用的空间和维护内存需要的辅助空间,请问 256 M B 256MB 256MB 的空间可以存储多少个 32 32 32 位二进制整数?

  • 解题思路

    1 M B = 2 10 K B = 2 20 B = 2 20 × 8 b i t 1MB=2^{10}KB=2^{20}B=2^{20}\times 8 bit 1MB=210KB=220B=220×8bit。换算输出即可。

  • 答案

    67108864 67108864 67108864


第二题 卡片

  • 问题描述

    小蓝有很多数字卡片,每张卡片上都是数字 0 0 0 9 9 9。小蓝准备用这些卡片来拼一些数,他想从 1 开始拼出正整数,每拼一个,就保存起来,卡片就不能用来拼其它数了。小蓝想知道自己能从 1 拼到多少。例如,当小蓝有 30 30 30 张卡片,其中 0 0 0 9 9 9 3 3 3 张,则小蓝可以拼出 1 到 10,但是拼 11 时卡片 1 已经只有一张了,不够拼出 11。现在小蓝手里有 0 到 9 的卡片各 2021 2021 2021 张,共 20210 20210 20210 张,请问小蓝可以从 1 1 1拼到多少?提示:建议使用计算机编程解决问题。

  • 解题思路

    直接模拟到用完为止,注意细节,最后退出的数需要减 1 1 1,因为我们拼不成。

  • 代码

/**
  *@filename:B
  *@author: pursuit
  *@CSDNBlog:unique_pursuit
  *@email: [email protected]
  *@created: 2021-04-18 14:37
**/
#include 

using namespace std;

typedef long long ll;
const int maxn = 100000 + 5;
const int mod = 1e9+7;

int n;
int a[10];
bool work(int x){
     
    while(x){
     
        int temp=x%10;
        x/=10;
        if(a[temp]>0){
     
            a[temp]--;
        }
        else{
     
            return false;
        }
    }
    return true;
}
int main(){
     
    while(cin>>n){
     
        for(int i=0;i<=9;i++)a[i]=n;
        int cnt=1;
        while(true){
     
            if(work(cnt)){
     
                cnt++;
            }
            else{
     
                break;
            }
        }
        cout<<cnt-1<<endl;//注意减1.
        //3181
    }
    return 0;
}
  • 答案

    3181 3181 3181


第三题 直线

  • 问题描述

    在平面直角坐标系中,两点可以确定一条直线。如果有多点在一条直线上,那么这些点中任意两点确定的直线是同一条。给定平面上 2 × 3 2 × 3 2×3个整点 ( x , y ) ∣ 0 ≤ x < 2 , 0 ≤ y < 3 , x ∈ Z , y ∈ Z {(x, y)|0 ≤ x < 2, 0 ≤ y < 3, x∈ Z, y ∈ Z} (x,y)0x<2,0y<3,xZ,yZ,即横坐标是 0 到 1 (包含 0 和 1) 之间的整数、纵坐标是 0 0 0 2 2 2 (包含 0 0 0 2 2 2) 之间的整数的点。这些点一共确定了 11 条不同的直线。给定平面上 20 × 21 个整点 ( x , y ) ∣ 0 ≤ x < 20 , 0 ≤ y < 21 , x ∈ Z , y ∈ Z {(x, y)|0 ≤ x < 20, 0 ≤ y < 21, x ∈ Z, y ∈ Z} (x,y)0x<20,0y<21,xZ,yZ,即横坐标是 0 0 0 19 19 19 (包含 0 0 0 19 19 19) 之间的整数、纵坐标是 0 到 20 (包含 0 0 0 20 20 20) 之间的整数的点。请问这些点一共确定了多少条不同的直线。

  • 解题思路

    写错了,以为是找规律,比赛的时候推的公式为 n + m + ( n − 1 ) ∗ n / 2 ∗ ( m − 1 ) ∗ m / 2 ∗ 2 n+m+(n-1)*n/2*(m-1)*m/2*2 n+m+(n1)n/2(m1)m/22正确解法利用直线判重解决这道题,表示直线的方式有很多种,这里采用斜截式来表示,通set容器来判重。需要注意的一个细节就是需要避免 k = 0 k=0 k=0 k = i n f k=inf k=inf的情况。 具体看代码。

  • 代码

/**
  *@filename:C
  *@author: pursuit
  *@CSDNBlog:unique_pursuit
  *@email: [email protected]
  *@created: 2021-04-18 14:40
**/
#include 

using namespace std;

typedef long long ll;
const int maxn = 100000 + 5;
const int mod = 1e9+7;

int n,m;
struct Point{
     
    int x,y;
    Point(){
     }
    Point(int x,int y){
     
        this->x=x,this->y=y;
    }
};
struct Line{
     
    //我们通过点斜式来确定一条直线,即y=kx+b;那么判重的方法就是判断k和b是不是相等的。
    double k,b;
    Line(){
     }
    Line(double k,double b){
     
        this->k=k,this->b=b;
    }
    //由于我们要利用set判重,故我们需要对<运算符重载。
    bool operator<(const Line &A)const {
     
        if(k==A.k)return b<A.b;
        return k<A.k;
    }
};
set<Line> t;
Point points[maxn];
int cnt=0;//点的个数。
void addLine(Point a1,Point a2){
     
    if(a1.x==a2.x||a1.y==a2.y)return;//对于k=0,或者k=无穷的情况我们不考虑,避免精度损失等问题。最后我们累加上这些即可。n+m。
    double temp=(a2.x-a1.x)*1.0;
    double k=(a2.y-a1.y)*1.0/temp;
    double b=(a1.y*a2.x-a1.x*a2.y)*1.0/temp;
    t.insert(Line(k,b));
}
int main(){
     
    cin>>n>>m;
    for(int i=0;i<n;i++){
     
        for(int j=0;j<m;j++){
     
            points[cnt++]=Point(i,j);
        }
    }
    //接下来确定直线加入set中。
    for(int i=0;i<cnt;i++){
     
        for(int j=0;j<cnt;j++){
     
            addLine(points[i],points[j]);
        }
    }
    cout<<t.size()+n+m<<endl;
    return 0;
}
  • 答案

    40257 40257 40257

第四题 货物摆放

  • 问题描述

    小蓝有一个超大的仓库,可以摆放很多货物。现在,小蓝有 n 箱货物要摆放在仓库,每箱货物都是规则的正方体。小蓝规定了长、宽、高三个互相垂直的方向,每箱货物的边都必须严格平行于长、宽、高。小蓝希望所有的货物最终摆成一个大的立方体。即在长、宽、高的方向上分别堆 L 、 W 、 H L、W、H LWH 的货物,满足 n = L × W × H n = L × W × H n=L×W×H。给定 n,请问有多少种堆放货物的方案满足要求。例如,当 n = 4 n = 4 n=4 时,有以下 6 种方案: 1 × 1 × 4 、 1 × 2 × 2 、 1 × 4 × 1 、 2 × 1 × 2 、 2 × 2 × 1 、 4 × 1 × 1 1×1×4、1×2×2、1×4×1、2×1×2、 2 × 2 × 1、4 × 1 × 1 1×1×41×2×21×4×12×1×22×2×14×1×1。请问,当 n = 2021041820210418 n = 2021041820210418 n=2021041820210418(注意有 16 16 16 位数字)时,总共有多少种方案?提示:建议使用计算机编程解决问题。

  • 解题思路

    枚举因子,由于不同顺序是不同的方案,所以我们先要假定 i ≤ j ≤ k i\leq j \leq k ijk,然后最后我们就可以对 i , j , k i,j,k i,j,k排列了,这样所有的情况都会被考虑,而因为都不相同的时候是 6 6 6种排列,有且只有两个相同的时候是 3 3 3种排列,都相同的时候是一种排列。所以我们需要统计满足条件的数目 c n t 0 cnt0 cnt0、满足条件的数目且其中有且仅有两个相同的数目 c n t 1 cnt1 cnt1、满足条件的数目有且仅有三个相同的数目 c n t 2 cnt2 cnt2。最后答案即是 c n t 0 × 6 − c n t 1 × 3 − c n t 2 × 5 cnt0\times 6-cnt1\times 3 - cnt2\times 5 cnt0×6cnt1×3cnt2×5

  • 代码

/**
  *@filename:B
  *@author: pursuit
  *@CSDNBlog:unique_pursuit
  *@email: [email protected]
  *@created: 2021-04-18 14:28
**/
#include 

using namespace std;

typedef long long ll;
const int maxn = 100000 + 5;
const int mod = 1e9+7;

ll n;
void solve(){
     
}
int main(){
     
    while(cin>>n){
     
        int cnt0=0,cnt1=0,cnt2=0;//cnt0统计所有情况,cnt1统计两个数相等的情况,cnt2统计三个数相等的情况
        for(ll i=1;i*i*i<=n;i++){
     
            if(n%i)continue;
            for(ll j=i;i*j*j<=n;j++){
     
                if(n%j)continue;
                ll k=n/(i*j);
                if(i*j*k==n){
     
                    cnt0++;
                    if(i==j&&j==k){
     
                        cnt2++;
                    }
                    else if(i==j||j==k||i==k){
     
                        cnt1++;
                    }
                }
            }
        }
        cout<<cnt0<<" "<<cnt1<<" "<<cnt2<<endl;//406 2 0
        //不相等6种排列,只有两个相等三种排列,三个相等一种排列。
        cout<<cnt0*6-cnt1*3-cnt2*5<<endl;//2430
    }
    solve();
    return 0;
}
  • 答案

    2430 2430 2430


第五题 路径

  • 问题描述

    小蓝学习了最短路径之后特别高兴,他定义了一个特别的图,希望找到图中的最短路径。小蓝的图由 2021 2021 2021 个结点组成,依次编号 1 1 1 2021 2021 2021。对于两个不同的结点 a , b a, b a,b,如果 a a a b b b 的差的绝对值大于 21 21 21,则两个结点之间没有边相连;如果 a a a b b b 的差的绝对值小于等于 21 21 21,则两个点之间有一条长度为 a a a b b b 的最小公倍数的无向边相连。例如:结点 1 1 1 和结点 23 23 23 之间没有边相连;结点 3 3 3 和结点 24 24 24 之间有一条无向边,长度为 24 24 24;结点 15 15 15 和结点 25 25 25 之间有一条无向边,长度为 75 75 75。请计算,结点 1 1 1 和结点 2021 2021 2021 之间的最短路径长度是多少。提示:建议使用计算机编程解决问题。

  • 解题思路

    最短路模板题。本题我采用 d i j k s t r a dijkstra dijkstra算法实现的。

  • 代码

/**
  *@filename:E
  *@author: pursuit
  *@CSDNBlog:unique_pursuit
  *@email: [email protected]
  *@created: 2021-04-18 14:50
**/
#include 

using namespace std;

typedef long long ll;
const int maxn = 10000 + 5;
const int mod = 1e9+7;
const int inf = 0x3f3f3f3f;

//最短路板子题。
int n;
int g[maxn][maxn];
int dist[maxn];
bool vis[maxn];
int gcd(int n,int m){
     
    return n%m?gcd(m,n%m):m;
}
void init(){
     
    memset(vis,0,sizeof(vis));
    for(int i=1;i<=n;i++){
     
        for(int j=1;j<=i;j++){
     
            if(abs(i-j)<=21){
     
                g[i][j]=g[j][i]=i*j/gcd(i,j);
            }
            else{
     
                g[i][j]=g[j][i]=inf;
            }
        }
    }
}
void dijkstra(int st){
     
    for(int i=1;i<=n;i++){
     
        dist[i]=g[st][i];
    }
    vis[st]=true;
    for(int i=1;i<=n;i++){
     
        int minn=inf,index;
        for(int j=1;j<=n;j++){
     
            if(!vis[j]&&dist[j]<minn){
     
                minn=dist[j];
                index=j;
            }
        }
        if(minn==inf)break;
        vis[index]=true;
        for(int j=1;j<=n;j++){
     
            if(!vis[j]&&dist[j]>dist[index]+g[index][j]){
     
                dist[j]=dist[index]+g[index][j];
            }
        }
    }
    cout<<dist[n]<<endl;//n=2021 print:10266837
}
void solve(){
     
    init();
    dijkstra(1);
}
int main(){
     
    while(cin>>n){
     
        solve();
    }
    return 0;
}
  • 答案

    10266837 10266837 10266837

程序题

第六题 时间显示

  • 问题描述

    小蓝要和朋友合作开发一个时间显示的网站。在服务器上,朋友已经获取了当前的时间,用一个整数表示,值为从 1970 1970 1970 1 1 1 1 1 1 00 : 00 : 00 00:00:00 00:00:00到当前时刻经过的毫秒数。现在,小蓝要在客户端显示出这个时间。小蓝不用显示出年月日,只需要显示出时分秒即可,毫秒也不用显示,直接舍去即可。给定一个用整数表示的时间,请将这个时间对应的时分秒输出。

    【输入格式】

    输入一行包含一个整数,表示时间。

    【输出格式】

    输出时分秒表示的当前时间,格式形如 H H : M M : S S HH:MM:SS HH:MM:SS,其中 H H HH HH 表示时,值为 0 0 0 23 23 23 M M MM MM 表示分,值为 0 0 0 59 59 59 S S SS SS 表示秒,值为 0 0 0 59 59 59。时、分、秒

    不足两位时补前导 0 0 0

    【样例输入 1】

    46800999 46800999 46800999

    【样例输出 1】

    13 : 00 : 00 13:00:00 13:00:00

    【样例输入 2】

    1618708103123 1618708103123 1618708103123

    【样例输出 2】

    01 : 08 : 23 01:08:23 01:08:23

    【评测用例规模与约定】

    对于所有评测用例,给定的时间为不超过 1018 的正整数。

  • 解题思路

    水题,转换时间。注意: 1 s = 1000 m s 1s=1000ms 1s=1000ms

  • AC代码

/**
  *@filename:F
  *@author: pursuit
  *@CSDNBlog:unique_pursuit
  *@email: [email protected]
  *@created: 2021-04-18 14:57
**/
#include 

using namespace std;

typedef long long ll;
const int maxn = 100000 + 5;
const int mod = 1e9+7;

ll n;
void solve(){
     
    n/=1000;
    printf("%02d:%02d:%02d\n",(n%(24*3600))/3600,n%3600/60,n%60);
}
int main(){
     
    while(cin>>n){
     
        solve();
    }
    return 0;
}

第七题 砝码称重

  • 问题描述

    你有一架天平和 N N N 个砝码,这 N N N个砝码重量依次是 W 1 , W 2 , ⋅ ⋅ ⋅ , W N W_1, W_2, · · · , W_N W1,W2,,WN。请你计算一共可以称出多少种不同的重量?注意砝码可以放在天平两边。

    【输入格式】

    输入的第一行包含一个整数 N N N

    第二行包含 N N N 个整数: W 1 , W 2 , W 3 , ⋅ ⋅ ⋅ , W N W_1, W_2, W_3, · · · , W_N W1,W2,W3,,WN

    【输出格式】

    输出一个整数代表答案。

    【样例输入】

    3

    1 4 6

    【样例输出】

    10

    【样例说明】

    能称出的 10 种重量是:1、2、3、4、5、6、7、9、10、11。

    1 = 1;

    2 = 6 − 4 (天平一边放 6,另一边放 4);

    3 = 4 − 1;

    4 = 4;

    5 = 6 − 1;

    6 = 6;

    7 = 1 + 6;

    9 = 4 + 6 − 1;

    10 = 4 + 6;

    11 = 1 + 4 + 6。

    【评测用例规模与约定】

    对于 50% 的评测用例, 1 ≤ N ≤ 15 1 ≤ N≤ 15 1N15

    对于所有评测用例, 1 ≤ N ≤ 100 1 ≤ N ≤ 100 1N100 N N N 个砝码总重不超过 100000 100000 100000

  • 解题思路

    我们可以先来定义一下,我们总认为称出的重量为左边减右边,也就是说如果要增加就放左边,如果要减少就放右边,否则不放。

    这种决策问题一看就是 d p dp dp了,然而比赛的时候也还是不知道该怎么处理,于是用dfs枚举。能过一半的样例。
    补题:看了大佬的写法,确实是背包问题的变种,三种决策,不过这个题我们不是用 m a x max max来判断,因为我们只关心能否凑成,所以只需要累加之前的状态即可。
    还有一种解法是利用 s e t set set来写的,暂时不能理解,不过也贴出来供大家参考。

  • d f s dfs dfs捡分代码

/**
  *@filename:G
  *@author: pursuit
  *@CSDNBlog:unique_pursuit
  *@email: [email protected]
  *@created: 2021-04-18 15:15
**/
#include 

using namespace std;

typedef long long ll;
const int maxn = 100000 + 5;
const int mod = 1e9+7;

//
int n;
int w[maxn];
int cnt[maxn];
int sum;
void dfs(int step,int ans){
     
    //step表示当前正在选择的砝码,ans为左边减右边的重量。
    if(step==n+1){
     
        //说明前n个已经选完了。
        if(ans<=0)return;
        cnt[ans]++;
        return;
    }
    dfs(step+1,ans+w[step]);//放左边。
    dfs(step+1,ans);//不放。
    dfs(step+1,ans-w[step]);//放右边。
}
void solve(){
     
    dfs(1,0);
    int ans=0;
    for(int i=1;i<=sum;i++){
     
        if(cnt[i]>0)ans++;
    }
    cout<<ans<<endl;
}
int main(){
     
    cin>>n;
    sum=0;
    for(int i=1;i<=n;i++){
     
        cin>>w[i];
        sum+=w[i];
    }
    solve();
    return 0;
}
  • 动态规划解题代码

/**
  *@filename:G砝码称重背包问题变种
  *@author: pursuit
  *@CSDNBlog:unique_pursuit
  *@email: [email protected]
  *@created: 2021-04-19 18:55
**/
#include 

using namespace std;

typedef long long ll;
const int maxn = 100000 + 5;
const int mod = 1e9+7;

//背包dp。累加三种方案数即可。
int n;
int w[105];
int dp[105][maxn<<2];//dp[i][j]表示的即是前i个砝码中能凑成重量j的方案数。
int main(){
     
	cin>>n;
	for(int i=1;i<=n;i++)cin>>w[i];
	//由于我们在进行决策的时候会出现负数,所以我们需要将数组进行偏移一个maxn确保枚举的时候不会出现错误。
	dp[0][maxn]=1;//注意设立起始值作为更新点。
	for(int i=1;i<=n;i++){
     
		for(int j=-maxn+w[i];j<=maxn;j++){
     
			//从小到大开始枚举。
			//不选,加上,减去三种决策。
			dp[i][j+maxn]=dp[i-1][j+maxn]+dp[i-1][j+maxn+w[i]]+dp[i-1][j+maxn-w[i]];
		}
	}
	int ans=0;//累加所有出现的状态。
	for(int j=maxn+1;j<=maxn*2;j++){
     
		if(dp[n][j])ans++;
	}
	cout<<ans<<endl;
	return 0;
}
  • s e t set set容器判重处理代码
/**
  *@filename:G砝码称重利用set巧解
  *@author: pursuit
  *@CSDNBlog:unique_pursuit
  *@email: [email protected]
  *@created: 2021-04-19 21:13
**/
#include 

using namespace std;

typedef long long ll;
const int maxn = 100000 + 5;
const int mod = 1e9+7;

int n,w[105];
set<int> t1,t2;
int sum;
bool vis[maxn];//判断是否出现。
int main(){
     
    cin>>n;
    for(int i=1;i<=n;i++)cin>>w[i];
    t1.insert(0),t2.insert(0);//以它们作为更新点。
    for(int i=1;i<=n;i++){
     
        //每次加入一个元素进去。
        for(auto &x:t1){
     
            t2.insert(x+w[i]);
            t2.insert(x-w[i]);
        }
        t1=t2;
    }
    for(auto &x:t1){
     
        vis[abs(x)]=true;
    }
    int ans=0;
    for(int i=1;i<=maxn;i++){
     
        if(vis[i])ans++;
    }
    cout<<ans<<endl;
    return 0;
}

第八题 杨辉三角形

  • 问题描述

    下面的图形是著名的杨辉三角形:

    2021年4月 第十二届蓝桥杯软件类省赛C++B组第一场 真题题解_第1张图片

    如果我们按从上到下、从左到右的顺序把所有数排成一列,可以得到如下数列:

    1 , 1 , 1 , 1 , 2 , 1 , 1 , 3 , 3 , 1 , 1 , 4 , 6 , 4 , 1 , . . . 1, 1, 1, 1, 2, 1, 1, 3, 3, 1, 1, 4, 6, 4, 1, ... 1,1,1,1,2,1,1,3,3,1,1,4,6,4,1,...

    给定一个正整数 N N N,请你输出数列中第一次出现 N N N 是在第几个数?

    【输入格式】

    输入一个整数 N 。 N。 N

    【输出格式】

    输出一个整数代表答案。

    【样例输入】

    6

    【样例输出】

    13

    【评测用例规模与约定】

    对于 20% 的评测用例, 1 ≤ N ≤ 10 1 ≤ N≤ 10 1N10

    对于所有评测用例, 1 ≤ N ≤ 1000000000 1 ≤N ≤ 1000000000 1N1000000000

  • 解题思路

    杨辉三角第 i i i行第 j j j列的数为 C i − 1 j − 1 C_{i-1}^{j-1} Ci1j1,那么我们直接枚举 i , j i,j i,j即可。不过有一个坑点,比赛的时候没想到,就是 C n 1 C_{n}^1 Cn1的时候,需要枚举 O ( n 2 ) O(n^2) O(n2),没有想到。哎,只能过的 20 % 20\% 20%的分。

  • 代码

/**
  *@filename:H
  *@author: pursuit
  *@CSDNBlog:unique_pursuit
  *@email: [email protected]
  *@created: 2021-04-18 15:00
**/
#include 

using namespace std;

typedef long long ll;
const int maxn = 100000 + 5;
const int mod = 1e9+7;

ll C(ll n,ll m){
     
    ll ans=1;
    for(ll i=n,j=1;i>=(n-m+1);i--,j++){
     
        ans=ans*i/j;
    }
    return ans;
}
ll n;
void solve(){
     
    if(n==1){
     
        cout<<1<<endl;
        return;
    }
    bool flag=false;
    for(ll i=3;;i++){
     
        for(ll j=1;j<i;j++){
     
            if(C(i-1,j)==n){
     
                flag=true;
                cout<<(i-1)*i/2+j+1<<endl;//不过好像没考虑n特别大的时候。。。即跑1e9*1e9跑不出。
                break;
            }
        }
        if(flag)break;
    }
}
int main(){
     
    while(cin>>n){
     
        solve();
    }
    return 0;
}

第九题 双向排序

  • 问题描述

    给定序列 ( a 1 , a 2 , ⋅ ⋅ ⋅ , a n ) = ( 1 , 2 , ⋅ ⋅ ⋅ , n ) a_1, a_2, · · · , a_n) = (1, 2, · · · , n) a1,a2,,an)=(1,2,,n),即 a i = i a_i = i ai=i。小蓝将对这个序列进行 m m m 次操作,每次可能是将 a 1 , a 2 , ⋅ ⋅ ⋅ , a q i a_1, a_2, · · · , a_{q_i} a1,a2,,aqi 降序排列,或者将 a q i , a q i + 1 , ⋅ ⋅ ⋅ , a n a_{q_i},a_{q_{i+1}}, ···,a_n aqi,aqi+1,,an 升序排列。请求出操作完成后的序列。

    【输入格式】

    输入的第一行包含两个整数 n , m n, m n,m,分别表示序列的长度和操作次数。

    接下来 m m m 行描述对序列的操作,其中第 i i i 行包含两个整数 p i , q i p_i, q_{i} pi,qi 表示操作类型和参数。当 p i p_i pi = 0 时,表示将 a 1 , a 2 , ⋅ ⋅ ⋅ , a q i a_1, a_2, · · · , a_{q_i} a1,a2,,aqi 降序排列;当 p i = 1 p_i = 1 pi=1 时,表示将 a q i , a q i + 1 , ⋅ ⋅ ⋅ , a n a_{q_i} , a_{q_{i+1}}, · · · , a_n aqi,aqi+1,,an 升序排列。

    【输出格式】
    输出一行,包含 n n n 个整数,相邻的整数之间使用一个空格分隔,表示操作完成后的序列。

    【样例输入】

    3 3

    0 3

    1 2

    0 2

    【样例输出】

    3 1 2

    【样例说明】

    原数列为 (1, 2, 3)。

    第 1 步后为 (3, 2, 1)。

    第 2 步后为 (3, 1, 2)。

    第 3 步后为 (3, 1, 2)。与第 2 步操作后相同,因为前两个数已经是降序了。

    【评测用例规模与约定】

    对于 30% 的评测用例, n , m ≤ 1000 n, m ≤ 1000 n,m1000

    对于 60% 的评测用例, n , m ≤ 5000 n, m ≤ 5000 n,m5000

    对于所有评测用例, 1 ≤ n , m ≤ 100000 , 0 ≤ p i ≤ 1 , 1 ≤ q i ≤ n 1 ≤ n, m ≤ 100000,0 ≤ p_i ≤ 1,1 ≤ q_i ≤ n 1n,m1000000pi11qin

  • 解题思路

    有点线段树的味道,但不知道怎么处理,所以只能暴力出奇迹了,能过 60 % 60\% 60%的数据。

  • 代码

/**
  *@filename:I
  *@author: pursuit
  *@CSDNBlog:unique_pursuit
  *@email: [email protected]
  *@created: 2021-04-18 15:58
**/
#include 

using namespace std;

typedef long long ll;
const int maxn = 100000 + 5;
const int mod = 1e9+7;

int n,m;
int main(){
     
    while(cin>>n>>m){
     
        vector<int> a(n);
        for(int i=0;i<n;i++)a[i]=i+1;
        int p,q;
        while(m--){
     
            cin>>p>>q;
            if(p)sort(a.begin()+q-1,a.end());
            else sort(a.begin(),a.begin()+q,greater<int>() );
        }
        for(int i=0;i<n;i++){
     
            cout<<a[i];
            i==n-1?cout<<endl:cout<<" ";
        }
    }
    return 0;
}

第十题 括号序列

  • 问题描述

    给定一个括号序列,要求尽可能少地添加若干括号使得括号序列变得合法,当添加完成后,会产生不同的添加结果,请问有多少种本质不同的添加结果。两个结果是本质不同的是指存在某个位置一个结果是左括号,而另一个是右括号。例如,对于括号序列 (((),只需要添加两个括号就能让其合法,有以下几种不同的添加结果:()()()、()(())、(())()、(()()) 和 ((()))。

    【输入格式】

    输入一行包含一个字符串 s s s,表示给定的括号序列,序列中只有左括号和右括号。

    【输出格式】

    输出一个整数表示答案,答案可能很大,请输出答案除以 1000000007 1000000007 1000000007(即 1 0 9 + 7 10^9 + 7 109+7) 的余数。

    【样例输入】

    ((()

    【样例输出】

    5

    【评测用例规模与约定】

    对于 40% 的评测用例, ∣ s ∣ ≤ 200 |s| ≤ 200 s200

    对于所有评测用例, 1 ≤ ∣ s ∣ ≤ 5000 1 ≤ |s| ≤ 5000 1s5000

  • 解题思路

    持续懵逼中,偷分都不知道怎么偷,待补。

  • 代码

总结

难度适中,梯度明显,整体还算OK,待结果出来还愿。希望能取得一个不错的结果。

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