【三】【算法分析与设计】第三届程序设计竞赛部分题目,竖式加法,竖式乘法,求序列差最大,小红的字符串,再编号,消灭飞龙,世界五子棋

竖式加法

链接:登录—专业IT笔试面试备考平台_牛客网 来源:牛客网

题目描述

小红对简单的加法很在行。

她想知道对于一个正整数A,她需要找到一个最小的正整数B,以确保A+B会产生进位。

输入描述:

输入共 T+1 行。

第一行一个整数表示 T组数据(1≤T≤10^5)

接下来T行,每行一个整数表示A(1≤A≤10^8)

输出描述:

输出共T行,表示最小的正整数B

示例1

输入

3

114514

1314520

100

输出

6

80

900

备注:

T(1≤T≤10^5)

A(1≤A≤10^8)

 
#include <iostream> // 包含标准输入输出库
#include <math.h> // 包含数学库
using namespace std;

int main() {
    int n; // 定义变量n表示数据组数
    long long nums; // 定义变量nums表示输入的正整数A
    int count; // 定义变量count用于记录A末尾有多少个连续的0
    cin >> n; // 输入数据组数n

    for (int i = 1; i <= n; i++) { // 遍历每组数据
        cin >> nums; // 输入正整数A
        count = 0; // 初始化count为0

        while (1) { // 循环判断A末尾的连续0
            if (nums % 10 == 0) { // 如果A末尾是0
                count++; // 计数器加1
                nums = nums / 10; // A除以10,去掉末尾的0
            } else {
                break; // 如果A末尾不是0,跳出循环
            }
        }

        int num = nums % 10; // 取A的最后一位非0数字
        // 计算最小的正整数B使得A+B产生进位,结果为(10 - num)乘以10的count次方
        cout << (int)((10 - num) * pow(10, count)) << endl; // 输出结果
    }
}

int、long、longlong的范围

int

  • 最小范围是 $$-2^{31}$$ 到 $$2^{31}-1$$。

  • 这可以近似表示为 $$-2.1 \times 10^9$$到 $$2.1 \times 10^9$$。

  • 所以,对于 int,使用 $$10^9$$。

long

  • 对于32位系统,long 的范围与 int 相同,即 $$-2.1 \times 10^9$$ 到 $$-2.1 \times 10^9$$,或 $$10^9$$。

  • 对于64位系统,long 的最小范围是 $$-2^{63}$$ 到 $$2^{63}-1$$,近似为 $$-9.2 \times 10^{18}$$ 到 $$9.2 \times 10^{18}$$。

  • 所以,对于 long,在64位系统上使用 $$10^{18}$$。

long long

  • long long 的范围至少是 $$-2^{63}$$ 到 $$2^{63}-1$$,近似表示为 $$-9.2 \times 10^{18}$$ 到 $$9.2 \times 10^{18}$$。

  • 因此,对于 long long,也是使用 $$10^{18}$$。

总结:

  • int: $$10^9$$

  • long (32位系统): $$10^9$$

  • long (64位系统) 和 long long: $$10^{18}$$

竖式乘法

链接:登录—专业IT笔试面试备考平台_牛客网 来源:牛客网

题目描述

今天,小红参加了数学课,老师教授了竖式乘法的计算方法。但是,由于小红上课时分神,只听懂了一部分。在小红看来,他对两个整数a和b的竖式乘法进行了如下的计算,例如有a =123,b=321

123

*321

-----

123

246

369

-----

738

现在,小红给出了a和b,希望你按照小红的竖式乘法计算一下它们的乘积。

输入描述:

第一行为一个t,表示有t组数据

接下来有t行,每行为a,b。

输出描述:

输出为t行,每行为一组答案。

示例1

输入

3

123 321

111 111

100 12

输出

738

333

300

备注:

1≤t≤10^3,

1≤a,b≤10^9

 
#include <iostream> // 包含标准输入输出库
using namespace std;

int main() {
    int n; // 定义变量n表示数据组数
    long long a, b; // 定义变量a和b表示两个整数
    cin >> n; // 输入数据组数n
    for (int i = 1; i <= n; i++) { // 遍历每组数据
        cin >> a >> b; // 输入两个整数a和b
        long long sum = 0; // 初始化sum为0,用于存储竖式乘法的结果
        while (1) { // 循环进行竖式乘法的计算
            if (b != 0) { // 如果b不等于0
                sum += (b % 10) * a; // 取b的最后一位与a相乘,并累加到sum
                b = b / 10; // b除以10,去掉最后一位
            } else { // 如果b等于0
                break; // 跳出循环
            }
        }
        cout << sum << endl; // 输出竖式乘法的结果
    }
}

求序列差最大

链接:登录—专业IT笔试面试备考平台_牛客网 来源:牛客网

题目描述

给出一个长度为n的序列a,定义bi为a1~ai中的最大值,ci为a1~ai中的最小值。

现在你可以将序列a重新排列,要求最大化

并输出这个最大的值。

输入描述:

第一行输入一个正整数n (1≤n≤10^5)

接下来一行 m个正整数表示序列a(1≤ai≤10^9)

输出描述:

输出一行一个整数,表示重排序列 a 后

的最大值。

示例1

输入

5

1 2 3 4 5

输出

16

示例2

输入

3

4 8 1

输出

14

备注:

n(1≤n≤10^5)

a(1≤ai≤10^9)

 
#include <iostream>
#include <vector>
#include<limits.h>
using namespace std;
int main() {
        int n;
        cin >> n;
        long long max = INT_MIN, min = INT_MAX;
        vector<int> a(n);
        for (auto& x : a) {
                cin >> x;
                if (x > max) max = x;
                if (x < min) min = x;
        }

        cout << (max - min)*(n - 1) << endl;

}

小红的字符串

链接:登录—专业IT笔试面试备考平台_牛客网 来源:牛客网

题目描述

小明收到了小红赠送的一个全由小写英文字母构成的字符串,但小明认为这个字符串看起来不够美观。

在小明看来,一个美观的字符串应当保证任何相邻的字符都不相同。他想知道,要将这个字符串转换成一个美观的字符串,至少需要添加多少个字符。

你只需告诉他,添加最少字符后的字符串长度是多少。

输入描述:

第一行一个数T(1≤T≤10)

接下来T行,每行一个有且仅有小写英文字母构成的字符串s(1≤|s|≤100000)

输出描述:

输出T行,每行一个数,表示美化后串的最短长度

示例1

输入

4

a

ab

abbc

aaabb

输出

1

2

5

8

备注:

1≤T≤10

1≤|s|≤100000

 
#include <iostream> // 包含标准输入输出库
#include <vector> // 包含向量库
#include <limits.h> // 包含INT_MIN和INT_MAX定义
using namespace std;

int main() {
    int n; // 定义变量n表示序列长度
    cin >> n; // 输入序列长度n
    long long max = INT_MIN, min = INT_MAX; // 初始化最大值max为最小整数,最小值min为最大整数
    vector<int> a(n); // 定义长度为n的向量a
    for (auto& x : a) { // 遍历向量a中的每个元素
        cin >> x; // 输入序列中的每个元素
        if (x > max) max = x; // 更新最大值max
        if (x < min) min = x; // 更新最小值min
    }

    cout << (max - min) * (n - 1) << endl; // 计算并输出结果(max - min) * (n - 1)
}

再编号

链接:登录—专业IT笔试面试备考平台_牛客网 来源:牛客网

题目描述

有一群人,每个人都有一个独特的标识编号ai。

再编号对于每个人的编号a是一种操作,记为a',满足

现在有一系列询问,共m次。每次询问给定一对x和t,表示经过t次再编号后,我们需要知道第x个人的新编号是多少。

由于结果可能非常大,因此我们需要对10^9+7取模。

输入描述:

第一行2个数n,m,表示人数和询问次数

接下来一行n个数,表示ai

接下来m行,每行2个数x,t,描述一次询问。

输出描述:

m行,第i行1个数表示第i次询问的答案对10^9+7取模的结果。

示例1

输入

4 3

1 2 3 4

1 0

2 2

4 1

输出

1

22

6

备注:

n ≤ 100000 , m ≤ 10000 , t ≤ 100000 , 1 ≤ a(i) ≤ 1000000000

 
#include <iostream> // 包含标准输入输出库
#include <vector> // 包含向量库
#include <limits.h> // 包含INT_MIN和INT_MAX定义
#include <numeric> // 包含标准库函数
#include <math.h> // 包含数学库

using namespace std;

int main() {
    const long long mod = 1e9 + 7; // 定义常量mod为10^9 + 7
    vector<long long> coefficient(100010); // 定义大小为100010的向量coefficient用于存储系数
    long long sum = 0; // 初始化sum为0,用于存储所有ai的和
    long n, m; // 定义变量n表示人数,m表示询问次数
    cin >> n >> m; // 输入人数和询问次数
    vector<long long> a(n); // 定义大小为n的向量a用于存储每个人的标识编号
    for (auto &x : a) { // 遍历向量a中的每个元素
        cin >> x; // 输入每个人的标识编号
        sum = (sum + x % mod) % mod; // 更新sum,计算所有标识编号的和并对mod取模
    }

    // 计算并存储系数coefficient
    for (int i = 1, j = 1; i <= 100010; i++) { // 遍历从1到100010
        coefficient[i] = (j - coefficient[i - 1] + mod) % mod; // 计算当前系数并对mod取模
        j = j * (n - 1) % mod; // 更新j为j乘以(n-1)并对mod取模
    }

    // 处理每次询问
    for (int i = 1; i <= m; i++) { // 遍历每次询问
        long x, t; // 定义变量x表示第x个人,t表示t次再编号
        cin >> x >> t; // 输入x和t

        long long ans = sum * coefficient[t]; // 计算初始答案ans为sum乘以coefficient[t]
        if (t % 2 == 0) { // 如果t是偶数
            cout << (ans + a[x-1] + mod) % mod << endl; // 输出结果(ans + a[x-1] + mod)对mod取模
        } else { // 如果t是奇数
            cout << (ans - a[x-1] + mod) % mod << endl; // 输出结果(ans - a[x-1] + mod)对mod取模
        }
    }
}

消灭飞龙

链接:登录—专业IT笔试面试备考平台_牛客网 来源:牛客网

时间限制:C/C++ 1秒,其他语言2秒

空间限制:C/C++ 262144K,其他语言524288K

64bit IO Format: %lld

题目描述

凯丽面对着一群共n只飞龙,它们排成一列,每只飞龙站在一个位置上。

她的攻击可以同时命中连续3个位置上的飞龙(也可以只击中一只,或者是相邻两只),每次攻击造成一点伤害。

当一只飞龙的血量降至零时,该飞龙被视为被消灭(但位置仍然保留)。

此外,她还拥有一个魔法,可以在战斗的任意时刻使用,但只能使用一次,能够直接消灭相邻的2个位置上的飞龙(即使只有一只飞龙也可以使用,位置仍然保留)。

请问,她最少需要发动多少次攻击,才能消灭所有飞龙?

因为她已经力竭,所以需要你这个聪明的朋友来帮帮她!

输入描述:

第一行一个数n,分别表示飞龙的数量

第二行共n个整数,第i个整数表示ai,表示第i只飞龙的血量

输出描述:

共一个数,表示需要挥出的斩击数

示例1

输入

复制10 3 2 2 2 3 1 1 2 1 2

10

3 2 2 2 3 1 1 2 1 2

输出

复制5

5

说明

对1,2使用魔法,接下来的斩击位置为:

3 4 5

3 4 5

5 6 7

8 9 10

8 9 10

备注:

1 ≤n≤10^6,0≤ai≤10^9

1.

定义前缀和dp1[i],表示消灭a数组[0~i]位置的飞龙需要的最少的斩击数,并且此时维护a数组中飞龙的剩余生命值。

定义前缀和dp2[i],表示消灭a数组[i~n-1]位置的飞龙需要的最少的斩击数,并且此时维护a数组中飞龙的剩余生命值。

2.

枚举所有需要用药水的位置,对于每一个位置计算需要的最少的斩击数是多少,统计所有情况的最小值。

3.

void mincut1(vector<LL>& dp, int left, int right, vector<LL> a) { //a[left,right]

计算前缀和数组dp1,left到right位置的状态值。实际上left==1,right==n。

a数组中0位置没有飞龙,飞龙从1~n位置。

4. dp[left - 1] = 0;

初始化0位置的值,状态转移方程是dp[i]=dp[i-1]+a[i]。

意思是花费最小斩击数消灭0~i-1位置飞龙,并且维护完a[i],a[i+1]的剩余生命值,此时花费最小斩击数消灭0~i位置飞龙的斩击数是多少。

是花费最小斩击数消灭消灭0~i-1位置飞龙加上i位置飞龙剩余的生命值,并维护后面的飞龙剩余生命值。

因此dp[0]=0。

5. for (int i = left; i <= right; i++) { dp[i] = dp[i - 1] + a[i];

此时说明砍了i,i+1,i+2位置飞龙a[i]次,看完之后维护i+1,i+2位置飞龙的剩余生命值。 if(i+1<=right) a[i + 1] = a[i + 1] - a[i] > 0 ? a[i + 1] - a[i] : 0; if(i+2<=right) a[i + 2] = a[i + 2] - a[i] > 0 ? a[i + 2] - a[i] : 0; } }

6.

计算前缀和dp2,同理可得。

void mincut2(vector<LL>& dp, int left, int right, vector<LL> a) { //a[left,right] dp[right + 1] = 0; for (int i = right; i >= left; i--) { dp[i] = dp[i + 1] + a[i]; if(i-1>=left) a[i - 1] = a[i - 1] - a[i] > 0 ? a[i - 1] - a[i] : 0; if(i-2>=left) a[i - 2] = a[i - 2] - a[i] > 0 ? a[i - 2] - a[i] : 0; } }

7.

枚举用魔法的所有可能位置位置。

for (int i = 1; i <= n; i++) { // [1,i-1][i,i+1][i+2,n] sum = min(sum, (i - 1 >= 1 ? dp1[i - 1] : 0) + (i + 2 <= n ? dp2[i + 2] : 0)); }

 
#include <iostream> // 包含标准输入输出库
using namespace std;
#include <vector> // 包含向量库
#include <climits> // 包含INT_MIN和INT_MAX定义
using LL = long long; // 定义LL为long long的别名

// 计算前缀和数组dp1,表示从left到right位置飞龙的最小斩击数
void mincut1(vector<LL>& dp, int left, int right, vector<LL> a) {
    dp[left - 1] = 0; // 初始化dp[left - 1]为0
    for (int i = left; i <= right; i++) { // 遍历从left到right的每个位置
        dp[i] = dp[i - 1] + a[i]; // 计算dp[i]为dp[i - 1]加上a[i]的值
        if (i + 1 <= right) a[i + 1] = a[i + 1] - a[i] > 0 ? a[i + 1] - a[i] : 0; // 更新i+1位置飞龙的剩余生命值
        if (i + 2 <= right) a[i + 2] = a[i + 2] - a[i] > 0 ? a[i + 2] - a[i] : 0; // 更新i+2位置飞龙的剩余生命值
    }
}

// 计算前缀和数组dp2,表示从right到left位置飞龙的最小斩击数
void mincut2(vector<LL>& dp, int left, int right, vector<LL> a) {
    dp[right + 1] = 0; // 初始化dp[right + 1]为0
    for (int i = right; i >= left; i--) { // 遍历从right到left的每个位置
        dp[i] = dp[i + 1] + a[i]; // 计算dp[i]为dp[i + 1]加上a[i]的值
        if (i - 1 >= left) a[i - 1] = a[i - 1] - a[i] > 0 ? a[i - 1] - a[i] : 0; // 更新i-1位置飞龙的剩余生命值
        if (i - 2 >= left) a[i - 2] = a[i - 2] - a[i] > 0 ? a[i - 2] - a[i] : 0; // 更新i-2位置飞龙的剩余生命值
    }
}

int main() {
    int n; // 定义变量n表示飞龙的数量
    cin >> n; // 输入飞龙的数量
    vector<LL> a(n + 3); // 定义大小为n+3的向量a,用于存储每只飞龙的血量
    vector<LL> dp1(n + 3); // 定义大小为n+3的向量dp1,用于存储前缀和
    vector<LL> dp2(n + 3); // 定义大小为n+3的向量dp2,用于存储前缀和

    for (int i = 1; i <= n; i++) { // 遍历每只飞龙
        cin >> a[i]; // 输入每只飞龙的血量
    }

    LL sum = LONG_LONG_MAX; // 初始化sum为long long类型的最大值

    if (n >= 3) { // 如果飞龙数量大于等于3
        mincut1(dp1, 1, n, a); // 调用mincut1函数计算dp1
        mincut2(dp2, 1, n, a); // 调用mincut2函数计算dp2
    } else if (n == 1 || n == 2) { // 如果飞龙数量为1或2
        cout << 0 << endl; // 输出0
        return 0; // 结束程序
    }

    for (int i = 1; i <= n; i++) { // 遍历每个位置
        // 计算sum为用药水消灭飞龙的最小斩击数
        sum = min(sum, (i - 1 >= 1 ? dp1[i - 1] : 0) + (i + 2 <= n ? dp2[i + 2] : 0));
    }
    cout << sum << endl; // 输出最小斩击数

    return 0; // 结束程序
}

世界五子棋

链接:登录—专业IT笔试面试备考平台_牛客网 来源:牛客网

题目描述

艾米最近沉迷于世界五子棋,她在棋盘上放了一些棋子。 世界五子棋的规则如下。

给定一个n*m的棋盘。棋盘上有两种棋子“1”和“2”,其中每种棋子分别计算得分。

假如相同种类的五个棋子连成相邻的一行,一列,或斜对角线的情况,每有五个这样的棋子,该种类棋子加1分。

艾米已经把她的棋子都摆在了棋盘上。

但是艾米并不太聪明的样子,她希望你,聪明的朋友,告诉她,她两种棋子的得分。

输入描述:

第一行两个整数n,m,表示棋盘的大小。

接下来输入一个n*m的矩阵,表示棋盘。

“1”,“2”表示该位置有对应的棋子。

“0”表示该位置没有棋子。

输出描述:

一行2个整数,以空格隔开,表示“1”,“2”两种棋子各自的得分。

示例1

输入

20 20

10202022021000221222

22111122221221101010

11211001210010001210

02222120211010112111

21220011111022120012

00111101111212221010

22122012211221212111

22102022221121110211

20222121122221221121

10012221102212201222

12110201221022101111

02212201100112112111

22111222202221211110

12112222222122102121

21021120121212010221

10222001121022022112

11111201112100221021

12112102021200111100

21021021011222222202

12021221122012111212

输出

10 12

备注:

1<=n,m<=1000

 
#include <iostream> // 包含标准输入输出库
#include <vector> // 包含向量库
using namespace std;

// 检查是否有连续的五个相同的棋子
bool checkFive(const vector<vector<int>>& board, int x, int y, int dx, int dy) {
    int count = 1; // 计数器,初始化为1
    int n = board.size(), m = board[0].size(); // 获取棋盘的行数和列数
    int cur = board[x][y]; // 当前棋子的类型

    for (int i = 1; i < 5; ++i) { // 检查接下来的四个位置
        int nx = x + i * dx; // 计算新位置的行
        int ny = y + i * dy; // 计算新位置的列
        if (nx >= n || ny >= m || ny < 0 || board[nx][ny] != cur) return false; // 如果越界或棋子类型不同,返回false
        count++; // 计数器加1
    }
    return count == 5; // 如果计数器等于5,返回true
}

// 主函数
int main() {
    int n, m; // 定义变量n和m表示棋盘的大小
    cin >> n >> m; // 输入棋盘的大小
    vector<vector<int>> board(n, vector<int>(m)); // 定义棋盘,大小为n*m
    vector<int> score(3, 0); // 定义得分数组,分别存储0, 1, 2的得分,实际上0不会被使用

    // 读入棋盘数据
    for (int i = 0; i < n; ++i) { // 遍历棋盘的每一行
        for (int j = 0; j < m; ++j) { // 遍历棋盘的每一列
            char ch; // 定义字符变量ch
            cin >> ch; // 输入字符
            board[i][j] = ch - '0'; // 将字符转换为整数并存储在棋盘中
        }
    }

    // 遍历棋盘
    for (int i = 0; i < n; ++i) { // 遍历棋盘的每一行
        for (int j = 0; j < m; ++j) { // 遍历棋盘的每一列
            if (board[i][j] == 0) continue; // 如果是空位,跳过
            // 检查四个方向
            if (j + 4 < m && checkFive(board, i, j, 0, 1)) score[board[i][j]]++; // 水平方向
            if (i + 4 < n && checkFive(board, i, j, 1, 0)) score[board[i][j]]++; // 垂直方向
            if (i + 4 < n && j + 4 < m && checkFive(board, i, j, 1, 1)) score[board[i][j]]++; // 主对角线方向
            if (i + 4 < n && j - 4 >= 0 && checkFive(board, i, j, 1, -1)) score[board[i][j]]++; // 副对角线方向
        }
    }

    // 输出结果
    cout << score[1] << " " << score[2] << endl; // 输出1号和2号棋子的得分

    return 0; // 返回0,程序结束
}

结尾

最后,感谢您阅读我的文章,希望这些内容能够对您有所启发和帮助。如果您有任何问题或想要分享您的观点,请随时在评论区留言。

同时,不要忘记订阅我的博客以获取更多有趣的内容。在未来的文章中,我将继续探讨这个话题的不同方面,为您呈现更多深度和见解。

谢谢您的支持,期待与您在下一篇文章中再次相遇!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

妖精七七_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值