Java && C++ 实现第十二届蓝桥杯 C++ B组 H杨辉三角形 I双向序列

175 阅读5分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第5天,点击查看活动详情

虽然是C++组的,但是和Java组的差不了两道题,大家都可以看一看 如有错误,还请佬 评论或私信指出(写的稍些急) 再也不肝博客了 /(ㄒoㄒ)/~~

(由于上传图片有限制,如果描述不清楚点击手写题解) 手写题解字丑,但是小编感觉会比文字看的直观一些(其实是不会用数学公式)

编程题测试数据

C++B组手写题解(如果访问出错,请刷新访问的页面即可(Nebo的问题))

当前页面的编程题均在C语言网成功运行 C语言网有各届蓝桥杯的题库 第十二届蓝桥杯编程题测试 刷题集

在这里插入图片描述

试题 H: 杨辉三角形

时间限制: 1.0s

内存限制: 256.0MB

本题总分:20 分

【问题描述】

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

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

数列:

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

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

【输入格式】

输入一个整数 N。

【输出格式】

输出一个整数代表答案。

【样例输入】

6

【样例输出】

13

【评测用例规模与约定】

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

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

image.png

package LanqiaobeiExam._12CB;

import java.util.Scanner;

/**
 * ClassName: H杨辉三角形
 * Package: LanqiaobeiExam._12CB
 *
 * @DATE: 2022/3/21 21:42
 * Author: asleep
 */
public class H杨辉三角形 {
    static int N;
    public static long C(long n, long m) {
        long res = 1L;
        for (long i = n, j = 1; j <= m; i--, j++) {
            res = res * i / j;
            if (res > N) {
                return res;
            }
        }
        return res;
    }
    public static boolean dichotomy(int k) {
        long left = k * 2, right = N;
        if (left > right) { // 已经没有可能了,杨辉三角右半边的数字都比左半边的数字对称
            return false;
        }
        while (left < right) {
            long mid = (right - left) / 2 + left;
            if (C(mid, k) >= N) {
                right = mid;
            } else {
                left = mid + 1;
            }
        }
        if (C(right, k) == N) {
//            System.out.println(right + " " + k);
            System.out.println(right * (right + 1) / 2 + k + 1);
            return true;
        }
        return false;
    }
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        N = sc.nextInt();
//        System.out.println(C(116, 8));
        for (int i = 16; i >= 0; i--) {
            if (dichotomy(i)) {
                break;
            }
        }

    }
}

#include "iostream"

using namespace std;

int N;

long C(long a, long b) {
    long res = 1;
    for (long i = a, j = 1; j <= b; i--, j++) {
        res = res * i / j;
        if (res > N) {
            break;
        }
    }
    return res;
}

bool dichotomy(int k) {
    long left = 2 * k, right = N;
    if (left > right) {
        return false;
    }
    while (left < right) {
        long mid = (left + right) / 2;
        if (C(mid, k) >= N) {
            right = mid;
        } else {
            left = mid + 1;
        }
    }
    if (C(right, k) == N) {
        cout << right * (right + 1) / 2 + k + 1;
        return true;
    }
    return false;
}



int main() {
    cin >> N;
    for (int i = 16; i >= 0; i--) {
        if (dichotomy(i)) {
            break;
        }
    }
    return 0;
}

试题 I: 双向排序

时间限制: 1.0s

内存限制: 256.0MB

本题总分:25 分

【问题描述】

给定序列 (a1, a2, · · · , an) = (1, 2, · · · , n),即 ai = i。

小蓝将对这个序列进行 m 次操作,每次可能是将 a1, a2, · · · , aqi 降序排列,

或者将 aqi , aqi+1, · · · , an 升序排列。

请求出操作完成后的序列。

【输入格式】

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

接下来 m 行描述对序列的操作,其中第 i 行包含两个整数 pi, qi 表示操作

类型和参数。当 pi = 0 时,表示将 a1, a2, · · · , aqi 降序排列;当 pi = 1 时,表示

将 aqi , aqi+1, · · · , an 升序排列。

【输出格式】

输出一行,包含 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;

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

对于所有评测用例,1 ≤ n, m ≤ 100000,0 ≤ ai ≤ 1,1 ≤ bi ≤ n。

image.png

package LanqiaobeiExam._12CB;

import org.w3c.dom.Node;

import java.util.ArrayList;
import java.util.Scanner;

/**
 * ClassName: I双向排序
 * Package: LanqiaobeiExam._12CB
 *
 * @DATE: 2022/3/22 19:04
 * Author: asleep
 */
public class I双向排序 {
    public static class Node {
        int p;
        int q;

        public Node(int p, int q) {
            this.p = p;
            this.q = q;
        }
    }
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int m = sc.nextInt();
        ArrayList<Node> list = new ArrayList<>();
        for (int i = 0; i < m; i++) {
            int p = sc.nextInt();
            int q = sc.nextInt();
            if (p == 0) {
                while (list.size() > 0 && list.get(list.size() - 1).p == 0) {   //相同前半段操作,选下标最靠右的
                    q = Math.max(q, list.get(list.size() - 1).q);
                    list.remove(list.size() - 1);
                }
                while (list.size() >= 2 && list.get(list.size() - 2).q <= q) {  //如果当前操作的下标比上次前半段操作下标靠右,则前两次操作无效
                    list.remove(list.size() - 1);
                    list.remove(list.size() - 1);
                }
                list.add(new Node(0, q));
            } else if (list.size() > 0) {
                while (list.size() > 0 && list.get(list.size() - 1).p == 1) {   //相同后半段操作,选下标最靠左的
                    q = Math.min(q, list.get(list.size() - 1).q);
                    list.remove(list.size() - 1);
                }
                while (list.size() >= 2 && list.get(list.size() - 2).q >= q) {  //当前操作下标比上次后半段操作靠左,则前两次操作无效
                    list.remove(list.size() - 1);
                    list.remove(list.size() - 1);
                }
                list.add(new Node(1, q));
            }
        }
//        for (Node node : list) {
//            System.out.print(node.p + " " + node.q + "    ");
//        }

        int left = 1, right = n, num = n;   //确定一下插入值,和未插入范围的左右边界
        int[] res = new int [n + 1];
        for (int i = 0; i < list.size(); i++) { //开始插入值,每次插入值都 -1
            if (list.get(i).p == 0) {
                while (right > list.get(i).q && left <= right) {    //前半段操作,从后向前插入,一定要保证插入范围在下标右面
                    res[right--] = num--;
                }
            } else {
                while (left < list.get(i).q && left <= right) { //后半段,从前向后插入,一定要保证插入范围在下标左面
                    res[left++] = num--;
                }
            }
            if (left > right) { //如果未插入范围已经没有了,则插入完成
                break;
            }
        }                           //第0次是前半段操作,第1次是后半段操作,……以此类推
        if (list.size() % 2 == 0) { //如果上面操作完还存在未插入的范围,则按照规律插入
            while (left <= right) {
                res[right--] = num--;
            }
        } else {
            while (left <= right) {
                res[left++] = num--;
            }
        }
//        System.out.println();
        for (int i = 1; i <= n; i++) {
            System.out.print(res[i] + " ");
        }
    }
}

#include "iostream"

using namespace std;

const int N = 100010;
int n, m;
pair<int, int> nums[N];
int res[N];

int main() {
    cin >> n >> m;
    int top = 0;
    while (m--) {   //筛选操作
        int p, q;
        cin >> p >> q;
        if (p == 0) {
            while (top && nums[top].first == 0) {
                q = max(q, nums[top--].second);
            }
            while (top >= 2 && nums[top - 1].second <= q) {
                top -= 2;
            }
            nums[++top] = {p, q};
        } else if (top) {
            while (top && nums[top].first == 1) {
                q = min(q, nums[top--].second);
            }
            while (top >= 2 && nums[top - 1].second >= q) {
                top -= 2;
            }
            nums[++top] = {p, q};
        }
    }
    int num = n, left = 1, right = n;   //数字放入数组
    for (int i = 1; i<= top; i++) {
        if (nums[i].first == 0) {
            while (right > nums[i].second && left <= right) {
                res[right--] = num--;
            }
        } else {
            while (left < nums[i].second && left <= right) {
                res[left++] = num--;
            }
        }
        if (left > right) {
            break;
        }
    }
            //这里是当上面还存在未操作的范围,接下面默认填充上
    if (top % 2 == 1) { //前半段降序操作   (第一步降序,第二步升序,降序,升序……   如果最后一步是奇数,就是降序操作)
        while (left <= right) {
            res[left++] = num--;
        }
    } else {
        while (left <= right) {
            res[right--] = num--;
        }
    }
    for (int i = 1; i <= n; i++) {
        cout << res[i] << " ";
    }
    return 0;
}