算法笔记上机训练实战指南刷题

算法笔记上机训练实战指南刷题记录

文章目录

  • 算法笔记上机训练实战指南刷题记录
    • 简单模拟
      • [B1001 害死人不偿命的(3n+1)猜想](#B1001 害死人不偿命的(3n+1)猜想)
      • [B1011 A+B 和 C](#B1011 A+B 和 C)
      • [B1016 部分A+B](#B1016 部分A+B)
      • [B1026 程序运行时间](#B1026 程序运行时间)
      • B1046划拳
      • B1008数组元素循环右移问题
      • [B1012 数字分类](#B1012 数字分类)
      • [B1018 锤子剪刀布](#B1018 锤子剪刀布)
      • [B1046 Shortest Distance](#B1046 Shortest Distance)
      • [1065 A+B and C (64bit)](#1065 A+B and C (64bit))
      • [B1010 一元多项式求导](#B1010 一元多项式求导)
      • [B1031 查验身份证](#B1031 查验身份证)
      • [A1002 A+B for Polynomials](#A1002 A+B for Polynomials)
      • [B1009 Product of Polynomials](#B1009 Product of Polynomials)
    • 查找元素
      • [B1041 考试座位号](#B1041 考试座位号)
      • [B1004 成绩排名](#B1004 成绩排名)
      • [B1028 人口普查](#B1028 人口普查)
    • 每天两题,持续更新中~

简单模拟

题号 题目 分数
B1001 害死人不偿命的(3n+1)猜想 15✔️
B1011 A+B 和 C 15✔️
B1016 部分A+B 15✔️
B1026 程序运行时间 15✔️
B1046 划拳 15✔️
B1008 数组循环右移问题 20✔️
B1012 数字分类 20✔️
B1018 锤子剪刀布 20✔️
A1042 Shuffling Machine 20✔️
A1046 Shortest Distance 20✔️
B1065 1065 A+B and C (64bit) 20 ✔️
B1010 一元多项式求导 20✔️
A1002 A+B for Polynomials 25✔️
A1009 Product of Polynomials 25✔️
B1031 查验身份证 15✔️

B1001 害死人不偿命的(3n+1)猜想

c++ 复制代码
#include <iostream>
using namespace std;
int n, cnt;

int main()
{
    cin >> n;
    while(n != 1)
    {
        if(n % 2)
            n = (3 * n + 1) / 2;
        else
             n /= 2;
        cnt ++;
    }
    cout << cnt << endl;
}

B1011 A+B 和 C

⚠️ A+B可能爆INT。需要开long long。

c++ 复制代码
#include <iostream>
using namespace std;
int n;
long long a, b, c;

int main()
{
    cin >> n;
    for(int i = 1; i <= n; i ++)
    {
        cin >> a >> b >> c;
        cout << "Case #" << i << ": " << (a + b > c ? "true" : "false") << endl;
    }
    return 0;
}

B1016 部分A+B

思路1:

枚举DA,DB出现的次数cntDA, cntDB, 计算PA, PB, 输出PA+PB

A,B用字符串存取,枚举DA,DB次数可以遍历A,B字符串。

c++ 复制代码
#include <iostream>
#include <cstring>
using namespace std;
string A, DA, B, DB;
int cntDA, cntDB;
long long resa, resb;
int main()
{
    cin >> A >> DA >> B >> DB;
    for(int i = 0; i < A.size(); i ++)
        cntDA += (A[i] == DA[0]);
    for(int i = 0; i < B.size(); i ++)
        cntDB += (B[i] == DB[0]);
    if(cntDA) resa = DA[0] - '0';
    if(cntDB) resb = DB[0] - '0';
    for(int i = 1; i < cntDA; i ++) resa = resa * 10 + (DA[0] - '0');
    for(int i = 1; i < cntDB; i ++) resb = resb * 10 + (DB[0] - '0');
    cout << resa + resb << endl;
    return 0;
}

思路2:

c++ 复制代码
#include <iostream>
#include <cstring>
using namespace std;
typedef long long LL;
LL PA, PB, A, DA, B, DB;;
int main()
{
    cin >> A >> DA >> B >> DB;
    while(A)
    {
        int x = A % 10;
        if(x == DA) PA = PA * 10 + DA;
        A /= 10;
    }
    while(B)
    {
        int x = B % 10;
        if(x == DB) PB = PB * 10 + DB;
        B /= 10;
    }
    cout << PA + PB << endl;
    return 0;
}

个人推荐思路2,纯粹的模拟做法。

B1026 程序运行时间

复制代码
#include <iostream>
using namespace std;
int c1, c2, t;

int main()
{
    cin >> c1 >> c2;
    // t = (c2 - c1 + 50) / 100;
    t = c2 - c1;
    if(t % 100 >= 50) t = t / 100 + 1;
    else t = t / 100;
    printf("%02d:%02d:%02d\n", t / 3600, t % 3600 / 60, t % 60);
}

B1046划拳

failA,failB记录各自输的次数

c++ 复制代码
#include <iostream>
using namespace std;
int failA, failB;
int n;

int main()
{
    cin >> n;
    while(n --)
    {
        int a1, a2, b1, b2;
        cin >> a1 >> a2 >> b1 >> b2;
        if(a1 + b1 == a2 && a1 + b1 != b2) failB ++;
        if(a1 + b1 == b2 && a1 + b1 != a2) failA ++;
    }
    cout << failA << " " << failB << endl;

    return 0;
}

B1008数组元素循环右移问题

⚠️题目没有给定M的最大值,不能认为M<N。读入后需要令M=M%N。

直接输出N-M到N-1号元素,再输出0---N - M - 1号元素。

c++ 复制代码
#include <iostream>
using namespace std;
const int N = 110;
int a[N];
int n, m;

int main()
{
    scanf("%d %d", &n, &m);
    m %= n;
    for(int i = 0; i < n; i ++)
        scanf("%d", &a[i]);
    for(int i = n - m; i < n; i ++)
        cout << a[i] << " ";
    for(int i = 0; i < n - m; i ++)
        cout << a[i] << " \n"[ i == n - m - 1];
    return 0;
}

B1012 数字分类

复制代码
#include <iostream>
using namespace std;
const int N = 1010;
int n;
int A1, A2, A3, A4, A5;
int cntA2, cntA4;
int a[N];

int main()
{
    cin >> n;
    for(int i = 1; i <= n; i ++)
    {
        cin >> a[i];
        if(a[i] % 10 == 0) A1 += a[i];
        if(a[i] % 5 == 1)
        {
            cntA2 ++;
            if(cntA2 % 2 == 1) A2 += a[i];
            else A2 += -1 * a[i];
            
        }
        if(a[i] % 5 == 2) A3 ++;
        if(a[i] % 5 == 3) A4 += a[i], cntA4 ++;
        if(a[i] % 5 == 4) A5 = max(A5, a[i]);
    }
    double a4 = A4 * 1.0 / cntA4;
    printf("%d %d %d %.1lf %d", A1, A2, A3, a4, A5);
    printf("%d %d %d %.1lf %d", A1, A2, A3, a4, A5);
    printf("%d %d %d %.1lf %d", A1, A2, A3, a4, A5);
    printf("%d %d %d %.1lf %d", A1, A2, A3, a4, A5);
    printf("%d %d %d %.1lf %d", A1, A2, A3, a4, A5);
    return 0;
}

B1018 锤子剪刀布

题目要求输出甲乙获胜,平局,输了的次数,还要输出获胜最多的手势。

按照字典序 B布 C锤子 J剪刀 顺序布赢锤子,锤子赢剪刀,剪刀赢布,用mp数组存对应的手势,mp[0] = 'B',

times_A[3], times_B[3]分别存甲乙,胜场,平场,输场次数。hand_A[3]和hand_B[3]存甲乙布,锤子,剪刀胜利次数。

c++ 复制代码
#include <iostream>
using namespace std;

char mp[3] = {'B', 'C', 'J'};
int n;
int times_A[3], times_B[3];
int hand_A[3], hand_B[3];
char c1, c2;
int k1, k2;

int change(char c)
{
    if(c == 'B') return 0;
    if(c == 'C') return 1;
    if(c == 'J') return 2;
}

int main()
{
    cin >> n;
    while(n --)
    {
        cin >> c1 >> c2;
        k1 = change(c1);
        k2 = change(c2);
        if((k1 + 1) % 3 == k2)//甲获胜
        {
            times_A[0] ++;
            times_B[2] ++;
            hand_A[k1] ++;
        }
        else if(k1 == k2)//平局
        {
            times_A[1] ++;
            times_B[1] ++;
        }
        else
        {
            times_A[2] ++;
            times_B[0] ++;
            hand_B[k2] ++;
        }
    }

    printf("%d %d %d\n", times_A[0], times_A[1], times_A[2]);
    printf("%d %d %d\n", times_B[0], times_B[1], times_B[2]);
    int id1 = 0, id2 = 0;
    for(int i = 0; i < 3; i ++)
    {
        if(hand_A[i] > hand_A[id1]) id1 = i;
        if(hand_B[i] > hand_B[id2]) id2 = i;
    }
    printf("%c %c\n", mp[id1], mp[id2]);

    return 0;
}

A1042 Shuffling Machine

复制代码
#include <iostream>
using namespace std;
const int N = 60;
char mp[5] = {'S', 'H', 'C', 'D', 'J'};
int Start[N], End[N], Next[N];
int k;

int main()
{
    cin >> k;
    for(int i = 1; i <= 54; i ++) Start[i] = i;
    
    for(int i = 1; i <= 54; i ++) cin >> Next[i];

    for(int step = 1; step <= k; step ++)
    {
        for(int i = 1; i <= 54; i ++)
        {
            End[Next[i]] = Start[i];
        }
        for(int i = 1; i <= 54; i ++)
        {
            Start[i] = End[i];
        }
    }

    for(int i = 1; i <= 54; i ++)
    {
        if(i != 1) printf(" ");
        Start[i] --;
        printf("%c%d", mp[Start[i] / 13], Start[i] % 13 + 1);
    }

    return 0;
}

B1046 Shortest Distance

前缀和思想 O(n)

c++ 复制代码
#include <iostream>
using namespace std;
const int N = 1e5 + 10;
int a[N];
int dis[N];
int n, m;

int main()
{
    cin >> n;
    for(int i = 1; i <= n; i ++)
    {
        cin >> a[i];
        dis[i] += dis[i - 1] + a[i];
    }
    cin >> m;
    while(m --)
    {
        int l, r;
        cin >> l >> r;
        if(l > r) swap(l , r);
        int res = dis[r - 1] - dis[l - 1];
        cout << min(res, dis[n] - res) << endl;
    }
    return 0;
}

1065 A+B and C (64bit)

溢出理解

在补码加法运算中,会出现溢出这种问题,可以将溢出理解为"循环补码"

比如三位机器数的加法,3+3 = 011 + 011 = 110 = -2

因此,我们可以得到这样的规律:

只有"正数+正数"才会上溢------正+正=负

只有"负数+负数"才会下溢------负+负=正

计组加减运算原理相关文章加减运算&溢出判断(计算机组成原理16)_单符号位判断溢出-CSDN博客

进行溢出判断

c++ 复制代码
#include <iostream>
using namespace std;
typedef long long LL;
int n;

int main()
{
    cin >> n;
    for(int i = 1; i <= n; i ++)
    {
        LL a , b, c;
        cin >> a >> b >> c;
        LL res = a + b;
        bool flag = false;
        if(a < 0 && b < 0 && res >= 0) flag = false;
        else if(a > 0 && b > 0 && res < 0) flag = true;
        else if(res > c) flag = true;
        else flag = false;
        if(flag)
        {
            printf("Case #%d: true\n", i);
        }
        else
        {
            printf("Case #%d: false\n", i);
        }
    }

    return 0;
}

B1010 一元多项式求导

经过测试,不存在n<0的测试点,多项式中只有常数项,输出0, 0即可,其他情况只需要输出常数项之前的求导

c++ 复制代码
#include <iostream>
using namespace std;
int main() {
    int a, b, flag = 0;
    while (cin >> a >> b) {
        if (b != 0) {
            if (flag == 1) cout << " ";
            cout << a * b << " " << b - 1;
            flag = 1;
        }
    }
    if (flag == 0) cout << "0 0";
    return 0;
}

胡凡老师的思路:

c++ 复制代码
#include <iostream>
using namespace std;
const int N = 1010;
int a[N];

int main()
{
    int k, e, count = 0;
    while(cin >> k >> e)
    {
        a[e] = k;
    }
    a[0] = 0;
    for(int i = 1; i <= 1000; i ++)
    {
        a[i - 1] = a[i] * i;
        a[i] = 0;
        if(a[i - 1] != 0) count ++;
    }
    if(count == 0) cout << "0 0";
    else
    {
        for(int i = 1000; i >= 0; i --)
        {
            if(a[i] != 0)
            {
                printf("%d %d", a[i], i);
                count --;
                if(count != 0) printf(" ");
            }
        }
    }
    return 0;
}

B1031 查验身份证

题意:计算身份证前17位,带权和,mod 11 求得效验码和18位,比较,输出校验失败的身份证号码,全部校验成功输出All passed

思路:weight数组存权重,Z数组存需要哈希的校验码,X存为10,校验时特判一下,X为10的情况即可

c++ 复制代码
#include <iostream>
using namespace std;
const int N = 20;
int weight[N] = {7, 9, 10,5,8,4,2,1,6,3,7,9,10,5,8,4,2};
int Z[N] = {1, 0, 10, 9, 8, 7, 6, 5, 4, 3, 2};
int cnt;
int n;
string card;

int main()
{
    cin >> n;
    while(n --)
    {
        cin >> card;
        int res = 0;
        for(int i = 0; i < 17; i ++)
        {
            res += (card[i] - '0') * weight[i];
        }
        int m = Z[res % 11];
        if(m != 10 && m != card[card.size() - 1] - '0')
        {
            cout << card << endl;
            cnt ++;
        }
        else if(m == 10 && card[card.size() - 1] != 'X')
        {
            cout << card << endl;
            cnt ++;
        }
    }
    if(cnt == 0) puts("All passed");
    return 0;
}

A1002 A+B for Polynomials

题意: 计算A + B 多项式,输出非零项数目,然后按照幂次从高到低依次输出系数。

思路:a[i]数组存幂次为i的项的系数,每次直接加进去,is_use数组判断每个幂次是不是被用到了。注意,计算数目的时候需要特判两项相加为0的情况。

c++ 复制代码
#include <iostream>
using namespace std;
const int N = 1010;
int n;
double a[N];
bool is_use[N];
int cnt = 0;

int main()
{
    int t = 2;
    while(t --)
    {
        cin >> n;
        while(n --)
        {
            int idx;
            double value;
            cin >> idx >> value;
            a[idx] += value;
            is_use[idx] = true;
        }
    }
    
    for(int i = 0; i <= 1000; i ++)
    {
        cnt += (is_use[i] && a[i] != 0);
    }
    cout << cnt;
    for(int i = 1000; i >= 0; i --)
    {
        if(is_use[i] && a[i] != 0)
        {
            printf(" %d %.1lf", i, a[i]);
        }
    }
    return 0;
}

B1009 Product of Polynomials

题意:计算两个多项式乘积

a[idx]存x的idx次方对应的系数,b[idx]存x的idx次方对应的系数,c存储答案,两重循环计算答案即可。

注意:两个多项式求积,指数是2*N级别,输出时需要注意,题目不难,细节扣了一会,30min左右完成。

c++ 复制代码
#include <iostream>
using namespace std;
const int N = 2020;
double a[N], b[N], c[N];
bool is_use[N];
int cnt, k;
int n;

int main()
{
    cin >> n;
    while(n --)
    {
        int idx;
        double value;
        cin >> idx >> value;
        a[idx] = value;
        k = max(k, idx);
    }
    cin >> n;
    while(n --)
    {
        int idx;
        double value;
        cin >> idx >> value;
        b[idx] = value;
        for(int i = 0; i <= k; i ++)
        {
            c[idx + i] += b[idx] * a[i];
        }
    }
    
    for(int i = 0; i <= 2000; i ++)
    {
        cnt += (c[i] != 0);
    }

    cout << cnt;
    for(int i = 2000; i >= 0; i --)
    {
        if(c[i] != 0)
        {
            printf(" %d %.1lf", i, c[i]);
        }
    }
    printf("\n");

    return 0;
}

查找元素

题号 题目 分数
B1041 考试座位号 15✔️
B1004 成绩排名 20✔️
B1028 人口普查 20✔️

B1041 考试座位号

题意:给出考生准考证号,试机号和考试号,要求根据试机号输出准考证和考试号。

思路:string数组query存储试机号对应的信息,细节,可以把准考证号和座位号字符串拼接,这样输出比较方便。

考虑存储O(n),查询的效率O(1)

c++ 复制代码
#include <iostream>
using namespace std;
const int N = 1010;
string query[N];
int n, m;

int main()
{
    cin >> n;
    while(n --)
    {
        string id, exam;
        int test;
        cin >> id >> test >> exam;
        id += " " + exam;
        query[test] = id;
    }
    cin >> m;
    for(int i = 1; i <= m; i ++)
    {
        int x;
        cin >> x;
        cout << query[x] << endl;
    }

    return 0;
}

B1004 成绩排名

string name, id;

int score;

int max_score, min_score = 1000;

string max_info, min_info;

模拟比较成绩就行。

c++ 复制代码
#include <iostream>
using namespace std;
string name, id;
int score;
int  max_score, min_score = 1000;
string max_info, min_info;

int n;


int main()
{
    cin >> n;
    while(n --)
    {
        cin >> name >> id >> score;
        name += " " + id;
        if(score > max_score)
        {
            max_score = score;
            max_info = name;
        }

        if(score < min_score)
        {
            min_score = score;
            min_info = name;
        }
    }
    cout << max_info << endl;
    cout << min_info << endl;

    return 0;
}

B1028 人口普查

因为看错题目意思想的屎山代码

c++ 复制代码
#include <bits/stdc++.h>
using namespace std;
string name, birth;
int max_age, min_age = 30000000;
string max_age_name, min_age_name;
int n, age;
int months[13] = {0, 31, 28, 31,30,31,30,31,31,30,31,30,31};
int cnt = 0;

int main()
{
    cin >> n;
    while(n --)
    {
        cin >> name >> birth;
        string date;
        for(int i = 0; i < birth.size(); i ++) 
        {
            if(birth[i] != '/')
                date += birth[i];
        }
        age = stoi(date);
        // cout << age << endl;
        if(age < 18140906 || age > 20140906) continue;
        // cout << age << endl;
        if(age > max_age)
        {
            max_age = age;
            max_age_name = name;
        }
        if(age < min_age)
        {
            min_age = age;
            min_age_name = name;
        }
        int year = age / 10000;
        int month = age / 100 % 100;
        int day = age % 100;
        if((year % 4 == 0 && year% 100 != 0) || year% 400 == 0) months[2] =29;
        else months[2] = 28;

        if(day <= months[month]) cnt ++;
        else cout << age << endl;
    }
    if(cnt)
    {
        cout << cnt  << " " << min_age_name << " " << max_age_name << endl;
    }
    else
    {
        cout << 0 << endl;
    }
}

每天两题,持续更新中~

另外:自制PAT做题倒计时插件自制 PTA(拼题A)平台 计时器浏览器插件

相关推荐
森焱森2 小时前
水下航行器外形分类详解
c语言·单片机·算法·架构·无人机
天水幼麟2 小时前
动手学深度学习-学习笔记(总)
笔记·深度学习·学习
QuantumStack4 小时前
【C++ 真题】P1104 生日
开发语言·c++·算法
天水幼麟4 小时前
动手学深度学习-学习笔记【二】(基础知识)
笔记·深度学习·学习
写个博客5 小时前
暑假算法日记第一天
算法
沧海一笑-dj5 小时前
【51单片机】51单片机学习笔记-课程简介
笔记·学习·51单片机·江科大·江科大学习笔记·江科大单片机·江科大51单片机
老虎06275 小时前
JavaWeb(苍穹外卖)--学习笔记04(前端:HTML,CSS,JavaScript)
前端·javascript·css·笔记·学习·html
hie988945 小时前
MATLAB锂离子电池伪二维(P2D)模型实现
人工智能·算法·matlab
杰克尼5 小时前
BM5 合并k个已排序的链表
数据结构·算法·链表