The 14th Blue Bridge Cup (Phase 2) Simulation Competition Test Questions and Solution C++

Question A

【Problem Description】

Please find a minimum number greater than 2022. After the number is converted into binary, the lowest 6 binary numbers are all 0.
Please submit the decimal form of this number as an answer.
  
【Answer submission】

This is a question of filling in the blanks with the result, you only need to calculate the result and submit it. The result of this question is an integer, only fill in this integer when submitting the answer, filling in redundant content will result in no scoring.

Solution: bit operations

can also be calculated directly

If the last six bits in binary are 0, the number is a multiple of 64

The first multiple of 64 greater than 2023 is 64 * 32 = 2048

// 答案 2048
#include <bits/stdc++.h>
using namespace std;

bool check(int x) {
    
    
    return (x & 63) == 0;
}

int main() {
    
    
    int x = 2023;
    while (!check(x)) {
    
    
    	x ++;
    }
    cout << x << endl;
    return 0;
}

Question B

【Problem Description】

We count from October 1, 1949 to October 2, 1949 as 1 day elapsed.
How many days have passed from October 1, 1949 to January 1, 2022?

【Answer submission】

This is a question of filling in the blanks with the result, you only need to calculate the result and submit it. The result of this question is an integer, only fill in this integer when submitting the answer, filling in redundant content will result in no scoring.

Problem solution: Leap year judgment

// 答案:26390
#include <bits/stdc++.h>
using namespace std;

bool check(int year) {
    
    
    return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
}

int main() {
    
    
    int ans = 0;
    for (int i = 1950; i < 2022; i ++) {
    
    
        ans += 365 + check(i);
    }
    ans += 31 + 30 + 31;
    cout << ans << endl;
    return 0;
}

Question C

【Problem Description】

8518 is a very special number. If you regard this number as a hexadecimal number, its value is (8518)16 = 8 * 16 * 16 * 16 + 5 * 16 * 16 + 1 * 16 + 8 = 34072, And 34072 is exactly an integer multiple of 8518.

9558 is also such a number, which is 38232 in hexadecimal.

In fact, the numbers 0 to 9 with a length of 1 are satisfied to be regarded as integer multiples (1 times) of themselves after hexadecimal.

Excuse me, except for the number whose length is 1, what is the smallest number that satisfies this condition?

【Answer submission】

This is a question of filling in the blanks with the result, you only need to calculate the result and submit it. The result of this question is an integer, only fill in this integer when submitting the answer, filling in redundant content will result in no scoring.

Solution: enumeration judgment

// 答案:1038
#include <bits/stdc++.h>
using namespace std;

bool check(int x) {
    
    
    int tmp = x;
    int sum = 0, bac = 1;
    while (tmp) {
    
    
        sum += (tmp % 10) * bac;
        bac *= 16;
        tmp /= 10;
    }
    return sum % x == 0;
}

int main() {
    
    
    int x = 10;
    while (!check(x)) {
    
    
        x ++;
    }
    cout << x << endl;
    return 0;
}

Question D

【Problem Description】

Xiaolan has a number matrix with 30 rows and 60 columns, and each number in the matrix is ​​a number between 0 and 9.

174094882455171152761423221685761892795431233411387427793198
650286024865090061389344606618496378829135984076361542097372
601657541200146071777733599818266038012509478351201640618984
143988087783837107349651099683484992553337438088068198972282
890781586124258626539246182119762952003918195325258677229419
698255491250839396799769357665825441616335532825361862146291
503649293440596342887581257444442930778730382520372975343211
325351222640703400531067500454956482168314849207060705673849
265774579830223671554026061117300483012903885770893074783710
083450145620356667677191627276513995926532444279237315785832
411595106453089134746365281031552217482363035280722591085079
053410485925413958279617719034175332412908745680774313630190
429314820559328748143552689295945058801322270313370955837837
939182801848609300876356583948397645861551964542532682663945
625356614462682551015176002433628234343684739800880514363921
982340231989891351425389287014819359798014755509282450440511
590838726938103384801541373585690893606978941566666714061214
952341523168827712604946036245881214982452998386986623826275
782780208928205527678781609589000725521486468983551558405472
149903035076783644195574734088152324666290493119955560594634
905391288186024902215444250421277955403412298227858394469856
607272647132163832860126054679347881638761723785858733108109
249157334220127702410373959720286708183036202841837581704881
367895556630088230650972282944827258473951902831431040790814
079538232104075905120989173307660289899942087873076421916033
622143260549608274076012938515668898707915863945382394851328
164677964192631597026176253407553188801750590935427267220117
591817866992665840378311257621611574856498432538327068011953
631534031790352912617015229051836886166704989498756486878095
690013558017746707412183571476823027885971347137127534455141

Now Xiaolan wants to draw a broken line from the first row and the first column of this matrix to the 30th row and 60th column. The line can only go horizontally to the right or vertically downward, and can only turn at places with numbers. Xiaolan wants to know what is the maximum sum of the numbers that such a line passes through.

【Answer submission】

This is a question of filling in the blanks with the result, you only need to calculate the result and submit it. The result of this question is an integer, only fill in this integer when submitting the answer, filling in redundant content will result in no scoring.

Problem Solution: Dynamic Programming

// 答案:592
#include <bits/stdc++.h>
using namespace std;

const int m = 30, n = 60;

char mat[m + 1][n + 2]; // mat: matrix
int dp[m + 1][n + 1];

int main() {
    
    
    for (int i = 1; i <= m; i ++) {
    
    
        cin >> (mat[i] + 1);
    }
    for (int i = 1; i <= m; i ++) {
    
    
        for (int j = 1; j <= n; j ++) {
    
    
            dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]) + mat[i][j] - '0';
        }
    }
    cout << dp[m][n] << endl;
    return 0;
}

Question E

【Problem Description】

Divide 2022 into the sum of different prime numbers, how many can it be divided into at most?

【Answer submission】

This is a question of filling in the blanks with the result, you only need to calculate the result and submit it. The result of this question is an integer, only fill in this integer when submitting the answer, filling in redundant content will result in no scoring.

Solution: memory search

// 答案:33
#include <bits/stdc++.h>
using namespace std;

vector<int> primes;
int mp[2023][2023];

bool is_prime(int x) {
    
    
    for (int i = 2; i * i <= x; i ++) {
    
    
        if (x % i == 0) return false;
    }
    return true;
}

// cur: current, idx: index
int dfs(int cur, int idx) {
    
    
    if (cur == 0) return 0;
    if (cur < primes[idx]) return -1;
    if (mp[cur][idx] != 0) return mp[cur][idx];
    int mx = -0x3f3f3f3f;
    for (int i = idx; i < primes.size() && cur >= primes[i]; i ++) {
    
    
        mx = max(mx, 1 + dfs(cur - primes[i], i + 1));
    }
    return mp[cur][idx] = mx;
}

int main() {
    
    
    for (int i = 2; i <= 2022; i ++) {
    
    
        if (is_prime(i)) primes.push_back(i);
    }
    
    // cout << primes.size() << endl;
    cout << dfs(2022, 0) << endl;

    return 0;
}

The following memory search has 3 parameters, the efficiency is not as good as the above, but it is more convenient to record the path and output

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

vector<int> primes;
bool mp[2023][400][50];
int ans = 0;
vector<int> stk;

bool is_prime(int x) {
    
    
    for (int i = 2; i * i <= x; i ++) {
    
    
        if (x % i == 0) return false;
    }
    return true;
}

void dfs(int cur, int idx, int cnt) {
    
    
    if (cur == 2022)  {
    
    
        ans = max(ans, cnt);
        if (cnt == 33) {
    
    
            for (int x : stk) cout << x << "+";
            cout << "\n";
        }
    }
    if (cur + primes[idx] > 2022) return;
    if (mp[cur][idx][cnt]) return;
    for (int i = idx; i < primes.size() && cur + primes[idx] <= 2022; i ++) {
    
    
        stk.push_back(primes[i]);
        dfs(cur + primes[i], i + 1, cnt + 1);
        stk.pop_back();
    }
    mp[cur][idx][cnt] = true;
}

int main() {
    
    
    for (int i = 2; i <= 2022; i ++) {
    
    
        if (is_prime(i)) primes.push_back(i);
    }

//    cout << primes.size() << endl;
    dfs(0, 0, 0);
    cout << ans << endl;

    return 0;
}

The output path is as follows:

2+3+5+7+11+13+17+19+23+29+31+37+41+43+47+53+59+61+67+71+73+79+83+89+97+101+103+107+109+113+127+139+163+

Question F

【Problem Description】

Xiaolan is copying a file. He has copied t seconds and c bytes. The file has s bytes in total. If the copying is carried out at a uniform speed, how many seconds will Xiaolan need to copy?

【Input format】

Enter a line containing three integers t, c, s, separated by a space between adjacent two integers.

【Output format】

Output an integer representing the answer. The data guarantees that the answer is exactly an integer.

【Sample input】

3 10 20

【Sample output】

3

【Sample input】

30 14 21

【Sample output】

15

[Evaluation use case scale and agreement]
  For 50% of the evaluation use cases, 1 <= t, c, s <= 10000.

Solution: Calculation

Multiply before dividing to avoid infinity

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

int main() {
    
    
    int t, c, s;
    cin >> t >> c >> s;
    cout << s * t / c - t<< endl;
    return 0;
}

Question G

【Problem Description】

Xiaolan has n words, but some of the words are repeated, please help Xiaolan remove the repeated words.
  
【Input format】

The first line of input contains a positive integer n, indicating the number of words in Xiaolan.
Next n lines, each line contains a word composed of lowercase letters.

【Output format】

Please output those words after removing repetitions. If a word appears multiple times, please keep the word that appears for the first time, remove the words that appear later, and output in the order of input.

【Sample input】

5
lanqiao
hi
hello
hello
lanqiao

【Sample output】

lanqiao
hi
hello

[Evaluation use case scale and agreement]

For all evaluation cases, 1 <= n <= 100, and the length of each word does not exceed 100.

Solution: hash collection

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

int n;
set<string> st;
string str;

int main() {
    
    
    cin >> n;
    for (int i = 0; i < n; i ++) {
    
    
        cin >> str;
        if (st.count(str)) continue;
        st.insert(str);
        cout << str << endl;
    }
    return 0;
}

Question H

【Problem Description】

A character string is called a palindrome if it reads the same from left to right as it reads from right to left. For example, lanqiaoaiqnal is a palindrome.

Xiaolan has a string, please add some characters to the right of this string to make it a palindrome.

If there are multiple solutions, please output the shortest palindrome string.

【Input format】

Enter a line containing a string consisting of lowercase English letters.

【Output format】

Output a line containing the answer.

【Sample input】

lanqiao

【Sample output】

lanqiaoaiqnal

【Sample input】

banana

【Sample output】

bananab

【Sample input】

noon

【Sample output】

noon

[Evaluation use case scale and agreement]

1 <= string length <= 100 for all benchmarks.

Solution: suffix palindrome

Find the longest suffix palindrome substring, then reverse the previous part and splicing

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

string str;

bool check(int i, int j) {
    
    
    while (i < j) {
    
    
        if (str[i] != str[j])
            return false;
        i ++;
        j --;
    }
    return true;
}

int main() {
    
    
    cin >> str;
    int n = str.length();
    for (int i = 0; i < n; i ++) {
    
    
        if (check(i, n - 1)) {
    
    
            string s = str.substr(0, i);
            reverse(s.begin(), s.end());
            cout << str << s << endl;
            return 0;
        }
    }
    return 0;
}

Question I

【Problem Description】

Given a matrix of letters. An X figure is composed of a central point and straight line segments drawn from the central point to four 45-degree oblique directions. The lengths of the four line segments are the same, and the letters on the four line segments are the same as those at the central point.

An X graph can be described by three integers r, c, L, where r, c indicate that the center point is located at row r and column c, and the positive integer L indicates the length of the drawn straight line segment. For each integer i between 1 and L, the graph X satisfies: row ri, column ci is the same as row r, column c, row ri, column c+i is the same as row r, column c, r Column ci of line +i is the same as column c of line r, and column c+i of line r+i is the same as column c of line r.

For example, in the letter matrix below, all letters L form an X pattern, and the middle 5 Ls also form an X pattern. All the letters Q form an X figure.

LAAALA
ALQLQA
AALQAA
ALQLQA
LAAALA

Given a matrix of letters, ask how many X shapes there are in it.

【Input format】

The first line of input contains two integers n, m, representing the number of rows and columns of the letter matrix, respectively.
The next n lines, each with m uppercase letters, are the given matrix.

【Output format】

Output a line containing an integer representing the answer.

【Sample input】

5 6
LAAALA
ALQLQA
AALQAA
ALQLQA
LAAALA

【Sample output】

3

[Evaluation use case scale and agreement]

For 50% of the evaluation cases, 1 <= n, m <= 10.
1 <= n, m <= 100 for all evaluation cases.

Solution: enumeration

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

const int M = 105, N = 105;

int m, n;
char mat[M][N];
int ans = 0;

bool valid(int i, int j) {
    
    
    return i >= 0 && i < m && j >= 0 && j < n;
}

void check(int r, int c) {
    
    
    char ch = mat[r][c];
    for (int i = 1; ; i ++) {
    
    
        if (!(valid(r - i, c - i) && mat[r - i][c - i] == ch)) return;
        if (!(valid(r - i, c + i) && mat[r - i][c + i] == ch)) return;
        if (!(valid(r + i, c - i) && mat[r + i][c - i] == ch)) return;
        if (!(valid(r + i, c + i) && mat[r + i][c + i] == ch)) return;
        ans ++;
    }
}

int main() {
    
    
    cin >> m >> n;
    for (int i = 0; i < m; i ++) {
    
    
        cin >> mat[i];
    }
    for (int i = 0; i < m; i ++) {
    
    
        for (int j = 0; j < n; j ++) {
    
    
            check(i, j);
        }
    }
    cout << ans << endl;
    return 0;
}

Question J

【Problem Description】

Xiaolan has a sequence a[1], a[2], ..., a[n], and each time two adjacent elements can be exchanged, the cost is the larger of the two elements.

May I ask, what is the minimum total cost to change the sequence into an increasing sequence from small to large through exchange?

【Input format】

The input line contains an integer n denoting the sequence length.
The second line contains n integers representing the given sequence.

【Output format】

The output line contains an integer representing the least cost value.

【Sample input】

4
1 5 2 1

【Sample output】

12

[Evaluation use case scale and agreement]

For 30% of the evaluation cases, 1 <= n <= 1000, 1 <= a[i] <= 1000.
For 60% of the evaluation cases, 1 <= n <= 50000, 1 <= a[i] <= 50000.
For all evaluation cases, 1 <= n <= 1000000, 1 <= a[i] <= 1000000.

Problem solution: greedy + line segment tree

The greedy rule is relatively easy to see

Each time the smallest number is found and moved to the far left, the cost is the sum of all elements on the left

However, this is not convenient to deal with the problem, and the reverse thinking becomes:

Every time the largest number is found and moved to the far right, the cost is to multiply the value by the number of elements on the right

At the same time, every time the number that is moved to the rightmost is considered to be deleted

To query the number of effective elements on the right side, you need something to implement: dynamically modify the value of a node and quickly query the sum of a certain interval

You can use a line segment tree or a tree array, I use a line segment tree to achieve

The value of each node on the initial tree is 1, select the largest (and larger subscript) number each time, query the number of valid elements on the right to calculate the answer, and then update the value of the corresponding node on the tree to 0

For single-point modification interval query requirements, it is more appropriate to use tree arrays, and the code is more concise, while line segment trees are more powerful. You can learn about both:

(This idea is not the optimal solution, interested friends can consider optimization)

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

typedef pair<int, int> pii;
const int N = 1E6 + 5;

int n, tmp;
pii a[N];
int nodes[N << 2];
long long ans = 0;

void push_up(int idx) {
    
    
    nodes[idx] = nodes[idx << 1] + nodes[idx << 1 | 1];
}
// 建树,初始化全为 1
void build(int idx, int l, int r) {
    
    
    if (l == r) {
    
    
        nodes[idx] = 1;
        return;
    }
    int mid = (l + r) >> 1;
    build(idx << 1, l, mid);
    build(idx << 1 | 1, mid + 1, r);
    push_up(idx);
}
// 查询 L 到 R 区间内的和
int query(int idx, int l, int r, int L, int R) {
    
    
    if (L <= l && r <= R) {
    
    
        return nodes[idx];
    }
    int mid = (l + r) >> 1;
    int res = 0;
    if (L <= mid)
        res += query(idx << 1, l, mid, L, R);
    if (mid + 1 <= R)
        res += query(idx << 1 | 1, mid + 1, r, L, R);
    return res;
}
// 更新 pos 节点的值(单点修改,使其加上 add 的值)
void update(int idx, int l, int r, int pos, int add) {
    
    
    if (l == r) {
    
    
        nodes[idx] += add;
        return;
    }
    int mid = (l + r) >> 1;
    if (mid >= pos)
        update(idx << 1, l, mid, pos, add);
    if (mid + 1 <= pos)
        update(idx << 1 | 1, mid + 1, r, pos, add);
    push_up(idx);
}

int main() {
    
    
    cin >> n;
    for (int i = 0; i < n; i ++) {
    
    
        cin >> tmp;
        a[i] = pii(tmp, i);	// pair 存放整数与下标,用于排序
    }
    build(1, 0, n - 1);	// 初始化树
    sort(a, a + n);		//排序(元素大小优先,其次下标)
	// 倒序遍历
    for (int i = n - 1; i >= 0; i --) {
    
    
        int idx = a[i].second;
        // 右侧有效元素个数
        int cnt = (idx == n - 1) ? 0 : query(1, 0, n - 1, idx + 1, n - 1);
        ans += (long long) a[i].first * cnt;
        // 使树上该节点值 -1
        update(1, 0, n - 1, idx, -1);
    }
    cout << ans << endl;
    return 0;
}

Summarize

It can be seen that this simulation competition has begun to touch the algorithm routines. For example, the fourth question is an introductory template question for dynamic programming, and the fifth question is a template for memorized search.

And the last question actually uses advanced data structures, which is really short for the simulation game. Fortunately, it is only a single-point modification, but it also needs to be matched with greed. It really cannot be said to be simple.

This also reminds those who haven't had much contact with algorithm routines to start getting serious and not just stay on grammar and logic

Most of the other questions are about enumeration and calculation, but they also have the style of the Blue Bridge Cup. Familiarizing yourself with the style of the Blue Bridge is also good for the official competition

Of course, if there are mistakes or omissions in the solution, please private message or point out in the comment area, thank you very much!

Guess you like

Origin blog.csdn.net/Cey_Tao/article/details/127970021