博客地址:https://blog.csdn.net/m0_46326495/article/details/137728637

A: 握手问题(5分)

问题描述

小蓝组织了一场算法交流会议,总共有 50 50 50 人参加了本次会议。在会议上,大家进行了握手交流。按照惯例他们每个人都要与除自己以外的其他所有人进行一次握手(且仅有一次)。但有 7 7 7 个人,这7 人彼此之间没有进行握手(但这 7 7 7 人与除这 7 7 7 人以外的所有人进行了握手)。请问这些人之间一共进行了多少次握手?
注意 A A A B B B 握手的同时也意味着 B B B A A A 握手了,所以算作是一次握手。

思路

组合数学口算题, C 50 2 − C 7 2 = 1204 C_{50}^2-C_{7}^2=1204 C502C72=1204

B: 小球反弹(5分)

问题描述

有一长方形,长为 343720 343720 343720 单位长度,宽为 233333 233333 233333 单位长度。在其内部左上角顶点有一小球(无视其体积),其初速度如图所示且保持运动速率不变,分解到长宽两个方向上的速率之比为 d x : d y = 15 : 17 dx : dy = 15 : 17 dx:dy=15:17。小球碰到长方形的边框时会发生反弹,每次反弹的入射角与反射角相等,因此小球会改变方向且保持速率不变(如果小球刚好射向角落,则按入射方向原路返回)。从小球出发到其第一次回到左上角顶点这段时间里,小球运动的路程为多少单位长度?答案四舍五入保留两位小数。

在这里插入图片描述

思路

也是数学题,最终返回左上角时,走过的水平路程和垂直路程一定是 343720 343720 343720 233333 233333 233333的偶数倍,并且水平路程与垂直路程之比一定为 15 : 17 15:17 15:17。写暴力去找结果即可,答案是 1100325199.77 1100325199.77 1100325199.77

代码:

#include <iostream>
#include <cmath>

using namespace std;
typedef long long ll;
const ll W = 233333;
const ll L = 343720;

int main() {
    for (ll x = 2; x <= 10000; x += 2) {
        for (ll y = 2; y <= 10000; y += 2) {
            if (15 * W * y == 17 * L * x) {
                printf("%llf", sqrt((L * x) * (L * x) + (W * y) * (W * y)));
                return 0;
            }
        }
    }
    return 0;
}

C: 好数(10分)

问题描述

一个整数如果按从低位到高位的顺序,奇数位(个位、百位、万位· · · )上的数字是奇数,偶数位(十位、千位、十万位· · · )上的数字是偶数,我们就称之为“好数”。给定一个正整数 N N N,请计算从 1 1 1 N N N 一共有多少个好数。

输入格式

一个整数 N N N

输出格式

一个整数代表答案

样例输入1

24

样例输出1

7

样例输入2

2024

样例输出2

150

样例说明

对于第一个样例, 24 24 24 以内的好数有 1 1 1 3 3 3 5 5 5 7 7 7 9 9 9 21 21 21 23 23 23,一共 7 7 7 个。

评测用例规模与约定

对于 10 % 10\% 10% 的评测用例, 1 ≤ N ≤ 1 0 2 1 ≤ N ≤ 10^2 1N102
对于 100 % 100\% 100% 的评测用例, 1 ≤ N ≤ 1 0 7 1 ≤ N ≤ 10^7 1N107

思路

正解应该是数位dp,但是感觉数据不大,暴力枚举也能过

#include <iostream>
#include <algorithm>

using namespace std;

int n;

bool inline judge(int x) {
    int k = 1;
    while (x) {
        if ((x & 1) != (k & 1)) {
            return false;
        }
        x /= 10;
        k++;
    }
    return true;
}

int main() {
    ios::sync_with_stdio(false);
    cout.tie(nullptr);
    cin >> n;
    int res = 0;
    for (int i = 1; i <= n; i += 2) if (judge(i)) res++;
    cout << res << endl;
    return 0;
}

D: R 格式(10分)

问题描述

小蓝最近在研究一种浮点数的表示方法: R R R 格式。对于一个大于 0 0 0 的浮点数 d d d,可以用 R R R 格式的整数来表示。给定一个转换参数 n n n,将浮点数转换为 R R R格式整数的做法是:

  1. 将浮点数乘以 2 n 2^n 2n;
  2. 四舍五入到最接近的整数。

输入格式

一行输入一个整数 n n n 和一个浮点数 d d d,分别表示转换参数,和待转换的浮点数

输出格式

输出一行表示答案: d d d R R R 格式表示出来的值

样例输入

2 3.14

样例输出

13

样例说明

3.14 × 2 2 = 12.56 3.14 × 2^2 = 12.56 3.14×22=12.56,四舍五入后为 13 13 13

评测用例规模与约定

对于 50 % 50\% 50% 的评测用例, 1 ≤ n ≤ 10 1 ≤ n ≤ 10 1n10 1 ≤ 1 ≤ 1 d d d 视为字符串时的长度 ≤ 15 ≤ 15 15
对于 100 % 100\% 100% 的评测用例, 1 ≤ n ≤ 1000 1 ≤ n ≤ 1000 1n1000 1 ≤ 1 ≤ 1 d d d 视为字符串时的长度 ≤ 1024 ≤ 1024 1024;保证 d d d 是小数,即包含小数点。

思路

高精度

#include <iostream>
#include <algorithm>

using namespace std;

string add(string a, string b) {
    string res;
    int carry = 0;
    int i = a.size() - 1;
    int j = b.size() - 1;
    while (i >= 0 || j >= 0) {
        int sum = carry;
        if (i >= 0) sum += a[i--] - '0';
        if (j >= 0) sum += b[j--] - '0';
        carry = sum / 10;
        res += to_string(sum % 10);
    }
    if (carry) res += to_string(carry);
    reverse(res.begin(), res.end());
    return res;
}

string mul(string a, string b) {
    string res = "0";
    int n = a.size();
    int m = b.size();
    for (int i = n - 1; i >= 0; i--) {
        int carry = 0;
        string temp;
        for (int j = m - 1; j >= 0; j--) {
            int sum = (a[i] - '0') * (b[j] - '0') + carry;
            carry = sum / 10;
            temp += to_string(sum % 10);
        }
        if (carry) temp += to_string(carry);
        reverse(temp.begin(), temp.end());
        for (int k = 0; k < n - 1 - i; k++) temp += "0";
        res = add(res, temp);
    }
    return res;
}

int main() {
    ios::sync_with_stdio(false);
    cout.tie(nullptr);
    int n;
    string d;
    cin >> n >> d;
    string res = "1";
    for (int i = 0; i < n; i++) res = mul(res, "2");
    int pos = 0;
    while (d[d.size() - 1 - pos] != '.') pos++;
    res = mul(res, d.substr(0, d.size() - pos - 1) + d.substr(d.size() - pos));
    string remain = "5";
    for (int i = 0; i < pos - 1; i++) remain += "0";
    res = add(res, remain);
    cout << res.substr(0, res.size() - pos) << endl;
    return 0;
}

E: 宝石组合(15分)

问题描述

在一个神秘的森林里,住着一个小精灵名叫小蓝。有一天,他偶然发现了一个隐藏在树洞里的宝藏,里面装满了闪烁着美丽光芒的宝石。这些宝石都有着不同的颜色和形状,但最引人注目的是它们各自独特的“闪亮度” 属性。每颗宝石都有一个与生俱来的特殊能力,可以发出不同强度的闪光。小蓝共找到了 N N N 枚宝石,第 i i i 枚宝石的“闪亮度” 属性值为 H i H_i Hi,小蓝将会从这 N N N 枚宝石中选出三枚进行组合,组合之后的精美程度 S S S 可以用以下公式来衡量:
S = H a H b H c × L C M ( H a , H b , H c ) L C M ( H a , H b ) × L C M ( H a , H c ) × L C M ( H b , H c ) S=H_aH_bH_c\times \frac{LCM(H_a,H_b,H_c)}{LCM(H_a,H_b)\times LCM(H_a,H_c)\times LCM(H_b,H_c)} S=HaHbHc×LCM(Ha,Hb)×LCM(Ha,Hc)×LCM(Hb,Hc)LCM(Ha,Hb,Hc)
其中 L C M LCM LCM 表示的是最小公倍数函数。
小蓝想要使得三枚宝石组合后的精美程度 S S S 尽可能的高,请你帮他找出精美程度最高的方案。如果存在多个方案 S S S 值相同,优先选择按照 H H H 值升序排列后字典序最小的方案。

输入格式

第一行包含一个整数 N N N 表示宝石个数。
第二行包含 N N N 个整数表示 N N N 个宝石的“闪亮度”。

输出格式

输出一行包含三个整数表示满足条件的三枚宝石的“闪亮度”。

样例输入

5
1 2 3 4 9

样例输出

1 2 3

评测用例规模与约定

对于 30 % 30\% 30% 的评测用例, 3 ≤ N ≤ 100 , 1 ≤ H i ≤ 1000 3 ≤ N ≤ 100, 1 ≤H_i ≤1000 3N100,1Hi1000
对于 60 % 60\% 60% 的评测用例, 3 ≤ N ≤ 2000 3 ≤ N ≤ 2000 3N2000
对于 100 % 100\% 100% 的评测用例, 3 ≤ N ≤ 1 0 5 , 1 ≤ H i ≤ 1 0 5 3 ≤ N ≤ 10^5, 1 ≤H_i ≤ 10^5 3N105,1Hi105

思路

找最大gcd(a[i],a[j],a[k]),里面的最小的三个数

#include <iostream>
#include <algorithm>
#include <vector>

using namespace std;

int a[100100], b[100100];
vector<int> vec[100100];
int n;

int main() {
    ios::sync_with_stdio(false);
    cout.tie(nullptr);
    cin >> n;
    int max_a = 0;
    for (int i = 1; i <= n; i++) {
        cin >> a[i];
        b[a[i]]++;
        max_a = max(max_a, a[i]);
    }
    sort(a + 1, a + 1 + n);
    for (int i = 2; i <= max_a; i++) {
        for (int j = i; j <= max_a; j += i) {
            for (int k = 1; k <= b[j]; k++) {
                if (vec[i].size() >= 3) break;
                vec[i].push_back(j);
            }
        }
    }
    for (int i = max_a; i >= 2; i--) {
        if (vec[i].size() >= 3) {
            cout << vec[i][0] << " " << vec[i][1] << " " << vec[i][2] << endl;
            return 0;
        }
    }
    cout << a[1] << " " << a[2] << " " << a[3] << endl;
    return 0;
}

F: 数字接龙(15分)

问题描述

小蓝最近迷上了一款名为《数字接龙》的迷宫游戏,游戏在一个大小为 N × N N × N N×N 的格子棋盘上展开,其中每一个格子处都有着一个 0... K − 1 0 ... K − 1 0...K1之间的整数。游戏规则如下:

  1. 从左上角 ( 0 , 0 ) (0, 0) (0,0) 处出发,目标是到达右下角 ( N − 1 , N − 1 ) (N − 1,N − 1) (N1,N1) 处的格子,每一步可以选择沿着水平/垂直/对角线方向移动到下一个格子。
  2. 对于路径经过的棋盘格子,按照经过的格子顺序,上面的数字组成的序列要满足: 0 , 1 , 2 , . . . , K − 1 , 0 , 1 , 2 , . . . , K − 1 , 0 , 1 , 2 , . . . 0,1,2, ... , K − 1, 0, 1,2, ... ,K − 1, 0, 1, 2, ... 0,1,2,...,K1,0,1,2,...,K1,0,1,2,...
  3. 途中需要对棋盘上的每个格子恰好都经过一次(仅一次)。
  4. 路径中不可以出现交叉的线路。例如之前有从 ( 0 , 0 ) (0, 0) (0,0) 移动到 ( 1 , 1 ) (1, 1) (1,1),那么再从 ( 1 , 0 ) (1, 0) (1,0) 移动到 ( 0 , 1 ) (0, 1) (0,1) 线路就会交叉。

为了方便表示,我们对可以行进的所有八个方向进行了数字编号,如下图 2 2 2 所示;因此行进路径可以用一个包含 0...7 0... 7 0...7 之间的数字字符串表示,如下图 1 1 1是一个迷宫示例,它所对应的答案就是: 41255214 41255214 41255214

在这里插入图片描述
现在请你帮小蓝规划出一条行进路径并将其输出。如果有多条路径,输出字典序最小的那一个;如果不存在任何一条路径,则输出 − 1 −1 1

输入格式

第一行包含两个整数 N N N K K K
接下来输入 N N N 行,每行 N N N 个整数表示棋盘格子上的数字。

输出格式

输出一行表示答案。如果存在答案输出路径,否则输出 − 1 −1 1

样例输入

3 3
0 2 0
1 1 1
2 0 2

样例输出

41255214

样例说明

行进路径如图 1 1 1 所示。

评测用例规模与约定

对于 80 % 80\% 80% 的评测用例, 1 ≤ N ≤ 5 1 ≤ N ≤ 5 1N5
对于 100 % 100\% 100% 的评测用例, 1 ≤ N ≤ 10 , 1 ≤ K ≤ 10 1 ≤ N ≤ 10, 1 ≤ K ≤ 10 1N10,1K10

思路

dfs

#include <iostream>
#include <algorithm>
#include <vector>

using namespace std;
const int dx[8] = {-1, -1, 0, 1, 1, 1, 0, -1};
const int dy[8] = {0, 1, 1, 1, 0, -1, -1, -1};
int n, k;
bool st[101][101], ss[11][11][11][11];
int a[101][101];
vector<string> s;

void dfs(int x, int y, string q) {
    if (x == n - 1 && y == n - 1) {
        if (q.size() == n * n - 1) {
            s.push_back(q);
        }
        return;
    }
    for (int i = 0; i < 8; i++) {
        int ax = x + dx[i], ay = y + dy[i];
        if (ax < 0 || ay < 0 || ax >= n || ay >= n) continue;
        if ((a[ax][ay]) != (a[x][y] + 1) % k) continue;
        if (!st[ax][ay] && i % 2 == 0) {
            st[ax][ay] = true;
            char qq = i + '0';
            dfs(ax, ay, q + qq);
            st[ax][ay] = false;
        } else if (!st[ax][ay] && i % 2 == 1 && !ss[x][y][ax][ay]) {
            st[ax][ay] = true;
            char qq = i + '0';
            if (i == 1) {
                ss[x - 1][y][ax + 1][ay] = true;
                ss[ax + 1][ay][x - 1][y] = true;
            }
            if (i == 3 || i == 5) {
                ss[x + 1][y][ax - 1][ay] = true;
                ss[ax - 1][ay][x + 1][y] = true;
            }
            dfs(ax, ay, q + qq);
            st[ax][ay] = false;
            if (i == 1) {
                ss[x - 1][y][ax + 1][ay] = false;
                ss[ax + 1][ay][x - 1][y] = false;
            }
            if (i == 3 || i == 5) {
                ss[x + 1][y][ax - 1][ay] = false;
                ss[ax - 1][ay][x + 1][y] = false;
            }
        }
    }
}

int main() {
    ios::sync_with_stdio(false);
    cout.tie(nullptr);
    cin >> n >> k;
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            cin >> a[i][j];
        }
    }
    string q;
    st[0][0] = true;
    dfs(0, 0, q);
    if (s.empty()) {
        cout << "-1";
    } else {
        sort(s.begin(), s.end());
        cout << s[0];
    }
    return 0;
}

G: 爬山(20分)

问题描述

小明这天在参加公司团建,团建项目是爬山。在 x x x 轴上从左到右一共有 n n n座山,第 i i i 座山的高度为 h i h_i hi。他们需要从左到右依次爬过所有的山,需要花费的体力值为 S = ∑ i = 1 n h i S=\sum^n_{i=1}h_i S=i=1nhi
然而小明偷偷学了魔法,可以降低一些山的高度。他掌握两种魔法,第一种魔法可以将高度为H 的山的高度变为 ⌊ h ⌋ ⌊\sqrt {h}⌋ h ,可以使用 P P P 次;第二种魔法可以将高度为 H H H 的山的高度变为 ⌊ H 2 ⌋ ⌊\frac{H}{2}⌋ 2H,可以使用 Q Q Q 次。并且对于每座山可以按任意顺序多次释放这两种魔法。
小明想合理规划在哪些山使用魔法,使得爬山花费的体力值最少。请问最优情况下需要花费的体力值是多少?

输入格式

输入共两行。
第一行为三个整数 n n n P P P Q Q Q
第二行为 n n n 个整数 h 1 , h 2 , . . . , h n h_1,h_2,... ,h_n h1h2...hn

输出格式

输出共一行,一个整数代表答案。

样例输入

4 1 1
4 5 6 49

样例输出

18

样例说明

将第四座山变为 ⌊ 49 ⌋ = 7 ⌊\sqrt{49}⌋ = 7 49 =7,然后再将第四座山变为 ⌊ 7 2 ⌋ = 3 ⌊ \frac{7}{2}⌋ = 3 27=3
体力值为 4 + 5 + 6 + 3 = 18 4 + 5 + 6 + 3 = 18 4+5+6+3=18

评测用例规模与约定

对于 20 % 20\% 20%的评测用例,保证 n ≤ 8 , P = 0 n ≤ 8,P = 0 n8P=0
对于 100 100% 100 的评测用例,保证 n ≤ 100000 , 0 ≤ P ≤ n , 0 ≤ Q ≤ n , 0 ≤ h i ≤ 100000 n ≤ 100000,0 ≤ P ≤ n,0 ≤ Q ≤ n,0 ≤ h_i ≤ 100000 n1000000Pn0Qn0hi100000

思路

贪心,维护一个堆,哪个魔法减少的更多就取哪个。

#include <iostream>
#include <algorithm>
#include <queue>
#include <cmath>

using namespace std;
typedef long long ll;
priority_queue<int, vector<int>, less<int>> pq;
int p, q;
int n;

int main() {
    ios::sync_with_stdio(false);
    cout.tie(nullptr);
    cin >> n >> p >> q;
    for (int i = 0; i < n; i++) {
        int temp;
        cin >> temp;
        pq.push(temp);
    }
    while (p != 0 && q != 0) {
        int cur = pq.top();
        pq.pop();
        if ((int) sqrt(cur) < (int) (cur / 2)) {
            p--;
            cur = (int) sqrt(cur);
        } else {
            q--;
            cur = (int) (cur / 2);
        }
        pq.push(cur);
    }
    while (p != 0) {
        int cur = pq.top();
        pq.pop();
        p--;
        cur = (int) sqrt(cur);
        pq.push(cur);
    }
    while (q != 0) {
        int cur = pq.top();
        pq.pop();
        q--;
        cur = (int) (cur / 2);
        pq.push(cur);
    }
    ll ans = 0;
    while (!pq.empty()) {
        ans += pq.top();
        pq.pop();
    }
    cout << ans << endl;
    return 0;
}

H: 拔河(20分)

问题描述

小明是学校里的一名老师,他带的班级共有 n n n 名同学,第 i i i 名同学力量值为 a i a_i ai。在闲暇之余,小明决定在班级里组织一场拔河比赛。
为了保证比赛的双方实力尽可能相近,需要在这 n n n 名同学中挑选出两个队伍,队伍内的同学编号连续: { a l 1 , a l 1 + 1 , . . . , a r 1 − 1 , a r 1 } \{a_{l_1} , a_{{l_1}+1},...,a_{{r_1}-1},a_{{r_1}}\} {al1,al1+1,...,ar11,ar1} { a l 2 , a l 2 + 1 , . . . , a r 2 − 1 , a r 2 } \{a_{l_2} , a_{{l_2}+1},...,a_{{r_2}-1},a_{{r_2}}\} {al2,al2+1,...,ar21,ar2},其中 l 1 ≤ r 1 < l 2 ≤ r 2 l_1 ≤ r_1 < l_2 ≤ r_2 l1r1<l2r2
两个队伍的人数不必相同,但是需要让队伍内的同学们的力量值之和尽可能相近。请计算出力量值之和差距最小的挑选队伍的方式。

输入格式

输入共两行。
第一行为一个正整数 n n n
第二行为 n n n 个正整数 a i a_i ai

输出格式

输出共一行,一个非负整数,表示两个队伍力量值之和的最小差距。

样例输入

5
10 9 8 12 14

样例输出

1

样例说明

其中一种最优选择方式:
队伍1: { a 1 ; a 2 ; a 3 } \{a_1; a_2; a_3\} {a1;a2;a3},队伍2: { a 4 ; a 5 } \{a_4; a_5\} {a4;a5},力量值和分别为 10 + 9 + 8 = 27 10 + 9 + 8 = 27 10+9+8=27 12 + 14 = 26 12 + 14 = 26 12+14=26,差距为 ∣ 27 − 26 ∣ = 1 |27 − 26| = 1 ∣2726∣=1

评测用例规模与约定

对于 20 % 20\% 20% 的评测用例, n ≤ 50 n ≤ 50 n50
对于 100 % 100\% 100% 的评测用例, n ≤ 1 0 3 , a i ≤ 1 0 9 n ≤ 10^3,a_i≤10^9 n103,ai109

思路

前缀和+set

#include <iostream>
#include <algorithm>
#include <set>
#include <cmath>

using namespace std;
typedef long long ll;

ll n;
ll num[1010] = {0};
ll pre[1010] = {0};
multiset<ll> mset;

int main() {
    ios::sync_with_stdio(false);
    cout.tie(nullptr);
    cin >> n;
    for (int i = 1; i <= n; i++) {
        cin >> num[i];
        pre[i] = pre[i - 1] + num[i];
    }
    for (int l = 1; l <= n; l++) {
        for (int r = l + 1; r <= n; r++) {
            mset.insert(pre[r] - pre[l]);
        }
    }
    ll res = 999999999;
    for (int r = 1; r < n; r++) {
        for (int l = 0; l < r; l++) {
            ll val = pre[r] - pre[l];
            auto it = mset.lower_bound(val);
            if (it != mset.end()) {
                res = min(res, abs(*it - val));
            }
            if (it != mset.begin()) {
                it--;
                res = min(res, abs(*it - val));
            }
        }
        for (int i = r + 1; i <= n; i++) {
            mset.erase(mset.find(pre[i] - pre[r]));
        }
    }
    cout << res << endl;
    return 0;
}
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐