持续创作,加速成长!这是我参与「掘金日新计划 · 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。
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。
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;
}