华为机试真题练习汇总(共 108 题)

华为机试真题练习汇总(共 108 题)

华为机试真题练习汇总(共 108 题)

题目来源:华为机试 - 牛客

标记 * 号的代表有难度的题目。

HJ1 字符串最后一个单词的长度

描述
计算字符串最后一个单词的长度,单词以空格隔开,字符串长度小于5000。(注:字符串末尾不以空格为结尾)

输入描述:
输入一行,代表要计算的字符串,非空,长度小于5000。

输出描述:
输出一个整数,表示输入字符串最后一个单词的长度。

代码 1:

#include <iostream>
using namespace std;

int main() {
    string s;
    //cin>>s;
    getline(cin, s);

    int n = s.length(), i = n-1;
    while(s[i]!=' ' && i>=0)
        i--;
    cout <<n-i-1<<endl;
    return 0;
}

代码 2:

#include <iostream>
using namespace std;

int main() {
    string s;
    while(cin>>s);
    cout<<s.length();
    return 0;
}

HJ2 计算某字符出现次数

描述
写出一个程序,接受一个由字母、数字和空格组成的字符串,和一个字符,然后输出输入字符串中该字符的出现次数。(不区分大小写字母)

输入描述:
第一行输入一个由字母、数字和空格组成的字符串,第二行输入一个字符(保证该字符不为空格)。

输出描述:
输出输入字符串中含有该字符的个数。(不区分大小写字母)

代码:

#include <iostream>
using namespace std;

int main() {
    string s;
    //cin >> s;
    getline(cin, s);
    char c;
    cin >> c;

    for (char& x : s)
        x = tolower(x);
    c = tolower(c);

    int count = 0;
    for (char& ch : s)
        if (ch == c)
            count++;
    cout << count << endl;
    return 0;
}
// 64 位输出请用 printf("%lld")

HJ3 明明的随机数

描述
明明生成了N个1到500之间的随机整数。请你删去其中重复的数字,即相同的数字只保留一个,把其余相同的数去掉,然后再把这些数从小到大排序,按照排好的顺序输出。

输入描述:
第一行先输入随机整数的个数 N 。 接下来的 N 行每行输入一个整数,代表明明生成的随机数。 具体格式可以参考下面的"示例"。

输出描述:
输出多行,表示输入数据处理后的结果

代码:

#include <iostream>
#include <unordered_set>
#include <vector>
#include <algorithm>
using namespace std;

int main() {
    unordered_set<int> s;
    int n, x;
    cin >> n;
    while (n--)
    {
        cin >> x;
        s.insert(x);
    }

    vector<int> v;
    for (auto it = s.begin(); it != s.end(); it++)
        v.push_back(*it);
    sort(v.begin(), v.end());
    for (int& x : v)
        cout << x << endl;
    return 0;
}
// 64 位输出请用 printf("%lld")

HJ4 字符串分隔

描述

  • 输入一个字符串,请按长度为8拆分每个输入字符串并进行输出;

  • 长度不是8整数倍的字符串请在后面补数字0,空字符串不处理。

输入描述:
连续输入字符串(每个字符串长度小于等于100)

输出描述:
依次输出所有分割后的长度为8的新字符串

代码:

#include <iostream>
using namespace std;

int main() {
    string s;
    cin >> s;
    int n = s.length();
    for (int i = 0; i <= n - 8; i += 8)
        cout << s.substr(i, 8) << endl;
    int last = n % 8;
    if (last) {
        int begin = n / 8 * 8;
        string temp = s.substr(begin);
        while (temp.size() < 8)
            temp.push_back('0');
        cout << temp << endl;
    }
    return 0;
}
// 64 位输出请用 printf("%lld")

HJ5 进制转换

描述
写出一个程序,接受一个十六进制的数,输出该数值的十进制表示。

输入描述:
输入一个十六进制的数值字符串。

输出描述:
输出该数值的十进制字符串。不同组的测试用例用\n隔开。

代码:

#include <cctype>
#include <cmath>
#include <iostream>
using namespace std;

int main()
{
    string s;
    cin >> s;

    int n = s.length(), mi = 0;
    long long ans = 0LL;
    for (int i = n - 1; i >= 0; i--)
    {
        if (s[i] == 'x')
            break;
        int digit = 0;
        if (isdigit(s[i]))
            digit = s[i] - '0';
        else
            digit = 10 + s[i] - 'A';
        
        ans += digit * (long long)pow(16, mi);
        mi++;
    }
    cout<<ans<<endl;
    return 0;
}
// 64 位输出请用 printf("%lld")

HJ6 质数因子

描述
功能:输入一个正整数,按照从小到大的顺序输出它的所有质因子(重复的也要列举)(如180的质因子为2 2 3 3 5 )

输入描述:
输入一个整数

输出描述:
按照从小到大的顺序输出它的所有质数的因子,以空格隔开。

代码:

#include <iostream>
using namespace std;

int main() {
    long long num;
    cin >> num;
    for (int i = 2; i * i <= num; i++) {
        if (num % i == 0) {
            while (num % i == 0) {
                cout << i << ' ';
                num /= i;
            }
        }
    }
    if (num > 1)
        cout << num << endl;
    return 0;
}
// 64 位输出请用 printf("%lld")

HJ7 取近似值

描述
写出一个程序,接受一个正浮点数值,输出该数值的近似整数值。如果小数点后数值大于等于 0.5 ,向上取整;小于 0.5 ,则向下取整。

数据范围:保证输入的数字在 32 位浮点数范围内

输入描述:
输入一个正浮点数值

输出描述:
输出该数值的近似整数值

代码:

#include <iostream>
using namespace std;

int main() {
    double input;
    cin >> input;
    int x = static_cast<int>(input);
    if (input - x >= 0.5)
        cout << x + 1 << endl;
    else
        cout << x << endl;
    return 0;
}
// 64 位输出请用 printf("%lld")

HJ8 合并表记录

描述
数据表记录包含表索引index和数值value(int范围的正整数),请对表索引相同的记录进行合并,即将相同索引的数值进行求和运算,输出按照index值升序进行输出。

提示:
0 <= index <= 11111111
1 <= value <= 100000

输入描述:
先输入键值对的个数n(1 <= n <= 500)
接下来n行每行输入成对的index和value值,以空格隔开

输出描述:
输出合并后的键值对(多行)

代码:

#include <algorithm>
#include <iostream>
#include <unordered_map>
#include <vector>
using namespace std;

int main() {
    int n;
    cin >> n;
    int index, value;
    unordered_map<int, int> cnt;
    for (int i = 0; i < n; i++) {
        cin >> index >> value;
        cnt[index] += value;
    }
    vector<pair<int, int>> vp;
    for (auto &[idx, c] : cnt)
        vp.emplace_back(make_pair(idx, c));

    sort(vp.begin(), vp.end(),
    [](const pair<int, int>& p1, const pair<int, int>& p2) {
        return p1.first < p2.first;
    });

    for (auto& p : vp) {
        cout << p.first << ' ' << p.second << endl;
    }
    return 0;
}
// 64 位输出请用 printf("%lld")

HJ9 提取不重复的整数

描述
输入一个 int 型整数,按照从右向左的阅读顺序,返回一个不含重复数字的新的整数。
保证输入的整数最后一位不是 0 。

输入描述:
输入一个int型整数

输出描述:
按照从右向左的阅读顺序,返回一个不含重复数字的新的整数

代码:

#include <iostream>
#include <string>
#include <unordered_set>
using namespace std;

int main() {
    int input;
    cin >> input;
    string s = to_string(input);
    int n = s.length();
    int ans = 0;
    unordered_set<int> us;
    for (int i = n - 1; i >= 0; i--) {
        int digit = s[i] - '0';
        if (us.count(digit))
            continue;
        ans = 10 * ans + digit;
        us.insert(digit);
    }
    cout << ans << endl;
    return 0;
}
// 64 位输出请用 printf("%lld")

HJ10 字符个数统计

描述
编写一个函数,计算字符串中含有的不同字符的个数。字符在 ASCII 码范围内( 0~127 ,包括 0 和 127 ),换行表示结束符,不算在字符里。不在范围内的不作统计。多个相同的字符只计算一次
例如,对于字符串 abaca 而言,有 a、b、c 三种不同的字符,因此输出 3 。

输入描述:
输入一行没有空格的字符串。

输出描述:
输出 输入字符串 中范围在(0~127,包括0和127)字符的种数。

代码:

#include <iostream>
#include <unordered_set>
using namespace std;

int main() {
    string s;
    cin >> s;
    unordered_set<char> us;
    for (char& c : s)
        us.insert(c);
    cout << us.size() << endl;
    return 0;
}
// 64 位输出请用 printf("%lld")

HJ11 数字颠倒

描述
输入一个整数,将这个整数以字符串的形式逆序输出
程序不考虑负数的情况,若数字含有0,则逆序形式也含有0,如输入为100,则输出为001

输入描述:
输入一个int整数

输出描述:
将这个整数以字符串的形式逆序输出

代码:

#include <iostream>
using namespace std;

int main() {
    int input;
    cin >> input;
    if (input == 0) {
        cout << "0" << endl;
        return 0;
    }
    string ans;
    while (input) {
        ans.push_back(input % 10 + '0');
        input /= 10;
    }
    cout << ans << endl;
    return 0;
}
// 64 位输出请用 printf("%lld")

HJ12 字符串反转

描述
接受一个只包含小写字母的字符串,然后输出该字符串反转后的字符串。(字符串长度不超过1000)

输入描述:
输入一行,为一个只包含小写字母的字符串。

输出描述:
输出该字符串反转后的字符串。

代码:

#include <algorithm>
#include <iostream>
using namespace std;

int main() {
    string s;
    cin >> s;
    reverse(s.begin(), s.end());
    cout << s << endl;
    return 0;
}
// 64 位输出请用 printf("%lld")

HJ13 句子逆序

代码:

#include <vector>
#include <iostream>
#include <sstream>
using namespace std;

int main()
{
    string s;
    getline(cin, s);
    stringstream ss(s);
    string word;

    vector<string> words;
    while (ss >> word)
        words.push_back(word);
    for (int i = words.size() - 1; i >= 0; i--)
    {
        if (i)
            cout << words[i] << ' ';
        else
            cout << words[i] << endl;
    }
    return 0;
}
// 64 位输出请用 printf("%lld")

HJ14 字符串排序

描述
给定 n 个字符串,请对 n 个字符串按照字典序排列。

输入描述:
输入第一行为一个正整数n(1≤n≤1000),下面n行为n个字符串(字符串长度≤100),字符串中只含有大小写字母。

输出描述:
数据输出n行,输出结果为按照字典序排列的字符串。

代码:

#include <algorithm>
#include <iostream>
#include <ostream>
#include <vector>
using namespace std;

int main() {
    int n;
    cin >> n;
    vector<string> words;
    for (int i = 0; i < n; i++)
    {
        string s;
        cin >> s;
        words.push_back(s);
    }
    sort(words.begin(), words.end());
    for (string word : words)
        cout << word << endl;
    return 0;
}
// 64 位输出请用 printf("%lld")

HJ15 求int型正整数在内存中存储时1的个数

描述
输入一个 int 型的正整数,计算出该 int 型数据在内存中存储时 1 的个数。

数据范围:保证在 32 位整型数字范围内

输入描述:
输入一个整数(int类型)

输出描述:
这个数转换成2进制后,输出1的个数

代码 1:

#include <iostream>
using namespace std;

int main() {
    int n;
    cin >> n;

    int count = 0;
    while (n) {
        count += n % 2;
        n >>= 1;
    }
    cout << count << endl;
    return 0;
}
// 64 位输出请用 printf("%lld")

代码 2:

n = n & (n-1),可以消去 n 二进制位中最右边的 1 个 1。

#include <iostream>
using namespace std;

int main() {
    int n;
    cin >> n;
    int count = 0;
    while (n) {
        n &= (n - 1);
        count++;
    }
    cout << count << endl;
    return 0;
}
// 64 位输出请用 printf("%lld")

* HJ16 购物单

代码:

#include <iostream>
#include <vector>
using namespace std;

int main() {
    int N, m;
    cin >> N >> m;
    // 价格
    vector<vector<int>> prices(61, vector<int>(3, 0));
    // 满意度是指所购买的每件物品的价格与重要度的乘积
    vector<vector<int> > favors(61, vector<int>(3, 0));
    for (int i = 1; i <= m; i++) {
        int v, p, q;
        // v 是价格,p 是重要度,q 是主件编号
        cin >> v >> p >> q;
        int favor = v * p;
        if (q == 0) {
            prices[i][0] = v;
            favors[i][0] = favor;
        } else {
            if (prices[q][1] == 0) {
                prices[q][1] = v;
                favors[q][1] = favor;
            } else {
                prices[q][2] = v;
                favors[q][2] = favor;
            }
        }
    }
    // 状态数组
    vector<vector<int> > dp(m + 1, vector<int>(N + 1, 0));
    // 状态转移
    for (int i = 1; i <= m; i++)
        for (int j = 1; j <= N; j++) {
            int p0 = prices[i][0], f0 = favors[i][0];
            int p1 = prices[i][1], f1 = favors[i][1];
            int p2 = prices[i][2], f2 = favors[i][2];
            // 状态转移方程
            dp[i][j] = dp[i - 1][j];
            if (j >= p0)
                dp[i][j] =  max(dp[i - 1][j - p0] + f0, dp[i - 1][j]);
            if (j >= (p0 + p1))
                dp[i][j] =   max(dp[i - 1][j - (p0 + p1)] + f0 + f1, dp[i][j]);
            if (j >= (p0 + p2))
                dp[i][j] =   max(dp[i - 1][j - (p0 + p2)] + f0 + f2, dp[i][j]);
            if (j >= (p0 + p1 + p2))
                dp[i][j] =  max(dp[i - 1][j - (p0 + p1 + p2)] + f0 + f1 + f2, dp[i][j]);
        }
        cout<<dp[m][N]<<endl;
        return 0;
}
// 64 位输出请用 printf("%lld")

HJ17 坐标移动

代码:

#include <cctype>
#include <iostream>
#include <sstream>
using namespace std;

int main()
{
    string str;
    cin >> str;

    stringstream ss(str);
    const char split = ';';
    string move;
    int x = 0, y = 0;
    while (getline(ss, move, split)) {
        char dir = move[0];
        bool judge = true;
        int distance = 0;
        for (int i = 1; i < move.length(); i++) {
            if (isdigit(move[i])) {
                distance = 10 * distance + move[i] - '0';
            } else {
                judge = false;
                break;
            }
        }
        if (judge) {
            switch (dir) {
                case 'A':
                    x -= distance;
                    break;
                case 'D':
                    x += distance;
                    break;
                case 'W':
                    y += distance;
                    break;
                case 'S':
                    y -= distance;
                    break;
                default:
                    break;
            }
        }
    }
    cout << x << "," << y << endl;
    return 0;
}
// 64 位输出请用 printf("%lld")

* HJ18 识别有效的IP地址和掩码并进行分类统计

代码:

#include <iostream>
#include <sstream>
#include <vector>
using namespace std;

bool judge_ip(const string ip) {
    int j = 0;
    stringstream ss(ip);
    string seg;
    while (getline(ss, seg, '.'))
        if (++j > 4 || seg.empty() || stoi(seg) > 255)
            return false;
    return j == 4;
}

bool is_mask(const string ip) {
    stringstream ss(ip);
    string seg;
    unsigned int b = 0;
    while (getline(ss, seg, '.'))
        b = (b << 8) + stoi(seg);

    if (b == 0 || ~b == 0) {
        // 二进制下全是1或者全是0均为非法子网掩码
        return false;
    }
    b = ~b + 1;
    if ((b & (b - 1)) == 0)
        return true;
    return false;
}

bool is_private(const string ip) {
    istringstream iss(ip);
    string seg;
    vector<int> v;
    while (getline(iss, seg, '.'))
        v.push_back(stoi(seg));
    if (v[0] == 10)
        return true;
    if (v[0] == 172 && (v[1] >= 16 && v[1] <= 31))
        return true;
    if (v[0] == 192 && v[1] == 168)
        return true;
    return false;
}

int main()
{
    string line;
    int a = 0, b = 0, c = 0, d = 0, e = 0, err = 0, p = 0;
    while (cin >> line) {
        int split_index = line.find('~');
        string ip = line.substr(0, split_index);
        string mask = line.substr(split_index + 1);

        int idx = ip.find_first_of('.');
        int first = stoi(ip.substr(0, idx));
        // 类似于【0.*.*.*】和【127.*.*.*】的IP地址不属于上述输入的任意一类,
        // 也不属于不合法ip地址,计数时请忽略
        if(first == 0 || first == 127)
            continue;
        if (!judge_ip(mask) || !is_mask(mask))
            err++;
        else {
            if (is_private(ip))
                p++;
            if (first >= 1 && first <= 126)
                a++;
            else if (first >= 128 && first <= 191)
                b++;
            else if (first >= 192 && first <= 223)
                c++;
            else if (first >= 224 && first <= 239)
                d++;
            else if (first >= 240 && first <= 255)
                e++;
        }
    }
    cout << a << " " << b << " " << c << " " << d << " " << e << " " << err << " "
         << p << endl;
    return 0;
}
// 64 位输出请用 printf("%lld")

* HJ19 简单错误记录

描述
开发一个简单错误记录功能小模块,能够记录出错的代码所在的文件名称和行号。

处理:

1、 记录最多8条错误记录,循环记录,最后只用输出最后出现的八条错误记录。对相同的错误记录只记录一条,但是错误计数增加。最后一个斜杠后面的带后缀名的部分(保留最后16位)和行号完全匹配的记录才做算是“相同”的错误记录。
2、 超过16个字符的文件名称,只记录文件的最后有效16个字符;
3、 输入的文件可能带路径,记录文件名称不能带路径。也就是说,哪怕不同路径下的文件,如果它们的名字的后16个字符相同,也被视为相同的错误记录
4、循环记录时,只以第一次出现的顺序为准,后面重复的不会更新它的出现时间,仍以第一次为准

输入描述:
每组只包含一个测试用例。一个测试用例包含一行或多行字符串。每行包括带路径文件名称,行号,以空格隔开。

输出描述:
将所有的记录统计并将结果输出,格式:文件名 代码行数 数目,一个空格隔开

代码:

#include <iostream>
#include <string>
#include <map>
#include <deque>
using namespace std;

int main() {
    string str;
    map<string, int> cnt;
    deque<string> dq;
    while (getline(cin, str)) {
        str = str.substr(str.find_last_of('\\') + 1);
        int pos = str.find_last_of(' ');
        if (pos > 16)
            str = str.substr(pos - 16);
        if (!cnt.count(str))
            dq.push_back(str);
        cnt[str]++;
        // 只保留最后出现的八条错误记录
        if (dq.size() > 8)
            dq.pop_front();
    }
    for (auto s : dq)
        cout << s << " " << cnt[s] << endl;
    return 0;
}
// 64 位输出请用 printf("%lld")

HJ20 密码验证合格程序

描述
密码要求:

1.长度超过8位

2.包括大小写字母.数字.其它符号,以上四种至少三种

3.不能有长度大于2的包含公共元素的子串重复 (注:其他符号不含空格或换行)

输入描述:
一组字符串。

输出描述:
如果符合要求输出:OK,否则输出NG

代码:

#include <iostream>
#include <vector>
using namespace std;

string passwordVerification(const string& s) {
    if (s.length() <= 8)
        return "NG";
    int n = s.length();
    // lower, upper, digit, other
    vector<bool> cnt(4, false);

    for (const char& ch : s) {
        if (islower(ch))
            cnt[0] = true;
        else if (isupper(ch))
            cnt[1] = true;
        else if (isdigit(ch))
            cnt[2] = true;
        else
            cnt[3] = true;
    }
    int count = 0;
    for (int i = 0; i < 4; i++)
        if (cnt[i])
            count++;
    if (count < 3)
        return "NG";
    for (int i = 0; i <= n - 6; i++) {
        string t1 = s.substr(i, 3);
        for (int j = i + 3; j <= n - 3; j++) {
            string t2 = s.substr(j, 3);
            if (t1 == t2)
                return "NG";
        }
    }
    return "OK";
}

int main()
{
    string pwd;
    while (getline(cin, pwd)) {
        cout << passwordVerification(pwd) << endl;
    }
    return 0;
}
// 64 位输出请用 printf("%lld")

HJ21 简单密码

描述
现在有一种密码变换算法。
九键手机键盘上的数字与字母的对应: 1–1, abc–2, def–3, ghi–4, jkl–5, mno–6, pqrs–7, tuv–8 wxyz–9, 0–0,把密码中出现的小写字母都变成九键键盘对应的数字,如:a 变成 2,x 变成 9.
而密码中出现的大写字母则变成小写之后往后移一位,如:X ,先变成小写,再往后移一位,变成了 y ,例外:Z 往后移是 a 。
数字和其它的符号都不做变换。

输入描述:
输入一组密码,长度不超过100个字符。

输出描述:
输出密码变换后的字符串

代码:

#include <iostream>
using namespace std;

string pwd_change(string& s) {
    for (char& ch : s) {
        if (islower(ch)) {
            switch (ch) {
                case 'a':
                case 'b':
                case 'c':
                    ch = '2';
                    break;
                case 'd':
                case 'e':
                case 'f':
                    ch = '3';
                    break;
                case 'g':
                case 'h':
                case 'i':
                    ch = '4';
                    break;
                case 'j':
                case 'k':
                case 'l':
                    ch = '5';
                    break;
                case 'm':
                case 'n':
                case 'o':
                    ch = '6';
                    break;
                case 'p':
                case 'q':
                case 'r':
                case 's':
                    ch = '7';
                    break;
                case 't':
                case 'u':
                case 'v':
                    ch = '8';
                    break;
                case 'w':
                case 'x':
                case 'y':
                case 'z':
                    ch = '9';
                    break;
            }
        } else if (isupper(ch)) {
            ch = (ch - 'A' + 1) % 26 + 'a';
        }
    }
    return s;
}

int main() 
{
    string pwd;
    cin >> pwd;
    cout << pwd_change(pwd) << endl;
    return 0;
}
// 64 位输出请用 printf("%lld")

HJ22 汽水瓶

描述
某商店规定:三个空汽水瓶可以换一瓶汽水,允许向老板借空汽水瓶(但是必须要归还)。
小张手上有n个空汽水瓶,她想知道自己最多可以喝到多少瓶汽水。

注意:本题存在多组输入。输入的 0 表示输入结束,并不用输出结果。

输入描述:
输入文件最多包含 10 组测试数据,每个数据占一行,仅包含一个正整数 n( 1<=n<=100 ),表示小张手上的空汽水瓶数。n=0 表示输入结束,你的程序不应当处理这一行。

输出描述:
对于每组测试数据,输出一行,表示最多可以喝的汽水瓶数。如果一瓶也喝不到,输出0。

代码:

#include <iostream>
using namespace std;

int main() {
    int n;
    while (cin >> n && n) {
        int drink = 0;
        while (n >= 3) {
            drink += n / 3;
            n = n % 3 + n / 3;
        }
        if (n == 2)
            drink++;
        cout << drink << endl;
    }
    return 0;
}
// 64 位输出请用 printf("%lld")

HJ23 删除字符串中出现次数最少的字符

描述
实现删除字符串中出现次数最少的字符,若出现次数最少的字符有多个,则把出现次数最少的字符都删除。输出删除这些单词后的字符串,字符串中其它字符保持原来的顺序。

输入描述:
字符串只包含小写英文字母, 不考虑非法输入,输入的字符串长度小于等于20个字节。

输出描述:
删除字符串中出现次数最少的字符后的字符串。

代码:

#include <climits>
#include <iostream>
#include <unordered_map>
using namespace std;

int main()
{
    string s;
    cin >> s;

    unordered_map<char, int> cnt;
    for (char& c : s)
        cnt[c]++;

    int min_cnt = INT_MAX;
    for (auto &[ch, count] : cnt)
        min_cnt = min(min_cnt, count);

    string ans;
    for (char& c : s)
        if (cnt[c] != min_cnt)
            ans += c;

    cout << ans << endl;
    return 0;
}
// 64 位输出请用 printf("%lld")

* HJ24 合唱队

代码:

#include <iostream>
#include <vector>
using namespace std;

int main() {
    int n ;
    cin >> n;
    vector<int> heights;
    for (int i = 0; i < n; i++) {
        int h;
        cin >> h;
        heights.push_back(h);
    }

    // 最长递增子序列
    vector<int> dp1(n, 0);
    for (int i = 0; i < n; i++) {
        dp1[i] = 1;
        for (int j = 0; j < i; j++)
            if (heights[i] > heights[j])
                dp1[i] = max(dp1[i], dp1[j] + 1);
    }
    // 最长递减子序列
    vector<int> dp2(n, 0);
    for (int i = n - 1; i >= 0; i--) {
        dp2[i] = 1;
        for (int j = n - 1; j > i; j--)
            if (heights[i] > heights[j])
                dp2[i] = max(dp2[i], dp2[j] + 1);
    }

    int maxlen = 0;
    for (int i = 0; i < n; i++) {
        int len = dp1[i] + dp2[i] - 1;
        maxlen = max(maxlen, len);
    }
    cout << n - maxlen << endl;

    return 0;
}
// 64 位输出请用 printf("%lld")

* HJ25 数据分类处理

描述
信息社会,有海量的数据需要分析处理,比如公安局分析身份证号码、 QQ 用户、手机号码、银行帐号等信息及活动记录。

采集输入大数据和分类规则,通过大数据分类处理程序,将大数据分类输出。

输入描述:
一组输入整数序列I和一组规则整数序列R,I和R序列的第一个整数为序列的个数(个数不包含第一个整数);整数范围为0~(231)-1,序列个数不限

输出描述:
从R依次中取出R,对I进行处理,找到满足条件的I:

I整数对应的数字需要连续包含R对应的数字。比如R为23,I为231,那么I包含了R,条件满足 。

按R从小到大的顺序:

(1)先输出R

(2)再输出满足条件的I的个数;

(3)然后输出满足条件的I在I序列中的位置索引(从0开始);

(4)最后再输出I。

附加条件:

(1)R需要从小到大排序。相同的R只需要输出索引小的以及满足条件的I,索引大的需要过滤掉

(2)如果没有满足条件的I,对应的R不用输出

(3)最后需要在输出序列的第一个整数位置记录后续整数序列的个数(不包含“个数”本身)

代码:

#include <algorithm>
#include <iostream>
#include <memory>
#include <vector>
using namespace std;

int main() {
    int n, m, num;
    vector<int> I, R;
    cin >> n;
    for (int i = 0; i < n; i++) {
        cin >> num;
        I.push_back(num);
    }
    cin >> m;
    for (int i = 0; i < m; i++) {
        cin >> num;
        R.push_back(num);
    }

    sort(R.begin(), R.end());

    vector<int> res;
    for (int i = 0; i < m; i++) {
        if (i && R[i] == R[i - 1])
            continue;
        // 满足条件的I的个数
        int count = 0;
        // 满足条件的I在I序列中的位置索引
        vector<int> index;
        for (int j = 0; j < n; j++)
            if (to_string(I[j]).find(to_string(R[i])) != string::npos) {
                count++;
                index.push_back(j);
            }
        if (count) {
            res.push_back(R[i]);
            res.push_back(count);
            for (int& idx : index) {
                res.push_back(idx);
                res.push_back(I[idx]);
            }
        }
    }

    // 先输出后续整数序列的个数
    cout << res.size();
    for (int& x : res)
        cout << " " << x;
    cout << endl;
    return 0;
}
// 64 位输出请用 printf("%lld")

* HJ26 字符串排序

描述
编写一个程序,将输入字符串中的字符按如下规则排序。

规则 1 :英文字母从 A 到 Z 排列,不区分大小写。

如,输入: Type 输出: epTy

规则 2 :同一个英文字母的大小写同时存在时,按照输入顺序排列。

如,输入: BabA 输出: aABb

规则 3 :非英文字母的其它字符保持原来的位置。

如,输入: By?e 输出: Be?y

输入描述:
输入字符串

输出描述:
输出字符串

代码:

#include <cctype>
#include <iostream>
#include <vector>
using namespace std;

int main() {
    string s;
    getline(cin, s);
    vector<char> alpha;
    for (int i = 0; i < 26; i++)
        for (char& c : s)
            if (c - 'a' == i || c - 'A' == i)
                alpha.push_back(c);
    int idx = 0;
    for (char& c : s)
        if (isalpha(c)) {
            c = alpha[idx];
            idx++;
        }
    cout << s << endl;
    return 0;
}
// 64 位输出请用 printf("%lld")

HJ27 查找兄弟单词

描述
定义一个单词的“兄弟单词”为:交换该单词字母顺序(注:可以交换任意次),而不添加、删除、修改原有的字母就能生成的单词。
兄弟单词要求和原来的单词不同。例如: ab 和 ba 是兄弟单词。 ab 和 ab 则不是兄弟单词。
现在给定你 n 个单词,另外再给你一个单词 x ,让你寻找 x 的兄弟单词里,按字典序排列后的第 k 个单词是什么?
注意:字典中可能有重复单词。

输入描述:
输入只有一行。 先输入字典中单词的个数n,再输入n个单词作为字典单词。 然后输入一个单词x 最后后输入一个整数k

输出描述:
第一行输出查找到x的兄弟单词的个数m 第二行输出查找到的按照字典顺序排序后的第k个兄弟单词,没有符合第k个的话则不用输出。

代码:

#include <algorithm>
#include <iostream>
#include <set>
#include <vector>
using namespace std;

bool isBrother(string s1, string s2) {
    if (s1.length() != s2.length())
        return false;
    if (s1 == s2)
        return false;
    sort(s1.begin(), s1.end());
    sort(s2.begin(), s2.end());
    return s1 == s2;
}

int main() {
    int n;
    cin >> n;
    vector<string> strDict;
    string word;
    for (int i = 0; i < n; i++) {
        cin >> word;
        strDict.push_back(word);
    }
    string x;
    cin >> x;
    int k;
    cin >> k;

    vector<string> brothers;
    for (string& s : strDict)
        if (isBrother(s, x))
            brothers.push_back(s);

    cout << brothers.size() << endl;
    if (brothers.size() >= k) {
        sort(brothers.begin(), brothers.end());
        cout << brothers[k - 1] << endl;
    }
    return 0;
}
// 64 位输出请用 printf("%lld")

** HJ28 素数伴侣

描述

若两个正整数的和为素数,则这两个正整数称之为“素数伴侣”,如2和5、6和13,它们能应用于通信加密。现在密码学会请你设计一个程序,从已有的 N ( N 为偶数)个正整数中挑选出若干对组成“素数伴侣”,挑选方案多种多样,例如有4个正整数:2,5,6,13,如果将5和6分为一组中只能得到一组“素数伴侣”,而将2和5、6和13编组将得到两组“素数伴侣”,能组成“素数伴侣”最多的方案称为“最佳方案”,当然密码学会希望你寻找出“最佳方案”。

输入:

有一个正偶数 n ,表示待挑选的自然数的个数。后面给出 n 个具体的数字。

输出:

输出一个整数 K ,表示你求得的“最佳方案”组成“素数伴侣”的对数。

代码:

#include <iostream>
#include <vector>
using namespace std;

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

bool find(int num, vector<int>& evens, vector<bool>& used, vector<int>& match) {
    // 遍历每个偶数与奇数比较
    for (int i = 0; i < evens.size(); i++) {
        if (isprime(num + evens[i]) && !used[i]) {
            used[i] = true;
            if (match[i] == 0 || find(match[i], evens, used, match)) {
                // 如果第i个偶数还未配对,或者跟它配对的奇数还有别的选择
                match[i] = num; // 则配对该数
                return true;
            }
        }
    }
    return false;
}

int main() {
    int n;
    cin >> n;
    vector<int> nums(n);
    vector<int> odd; // 奇数
    vector<int> even; // 偶数
    for (int i = 0; i < n; i++) {
        cin >> nums[i];
        if (nums[i] % 2)
            odd.push_back(nums[i]);
        else
            even.push_back(nums[i]);
    }

    // 特判
    if (odd.empty() || even.empty()) {
        cout << 0 << endl;
        return 0;
    }

    int count = 0;
    vector<int> match(even.size(), 0); // 统计每个偶数的配对是哪个奇数
    // 遍历每个奇数
    for (int i = 0; i < odd.size(); i++) {
        vector<bool> used(even.size(), false); // 每一轮偶数都没用过
        // 能否找到配对的偶数,且要最优
        if (find(odd[i], even, used, match))
            count++;
    }
    cout << count << endl;

    return 0;
}
// 64 位输出请用 printf("%lld")

HJ29 字符串加解密

描述
对输入的字符串进行加解密,并输出。

加密方法为:

当内容是英文字母时则用该英文字母的后一个字母替换,同时字母变换大小写,如字母a时则替换为B;字母Z时则替换为a;

当内容是数字时则把该数字加1,如0替换1,1替换2,9替换0;

其他字符不做变化。

解密方法为加密的逆过程。

输入描述:
第一行输入一串要加密的密码
第二行输入一串加过密的密码

输出描述:
第一行输出加密后的字符
第二行输出解密后的字符

代码:

#include <cctype>
#include <iostream>
using namespace std;

string encrypt(string& s) {
    for (char& c : s) {
        if (isalpha(c)) {
            if (islower(c))
                c = (c - 'a' + 1) % 26 + 'A';
            else
                c = (c - 'A' + 1) % 26 + 'a';
        } else if (isdigit(c))
            c = (c - '0' + 1) % 10 + '0';
    }
    return s;
}

string decrypt(string& s) {
    for (char& c : s) {
        if (isalpha(c)) {
            if (islower(c))
                c = (c - 'a' + 25) % 26 + 'A';
            else
                c = (c - 'A' + 25) % 26 + 'a';
        } else if (isdigit(c))
            c = (c - '0' + 9) % 10 + '0';
    }
    return s;
}

int main() {
    string s1;
    cin >> s1;
    cout << encrypt(s1) << endl;

    string s2;
    cin >> s2;
    cout << decrypt(s2) << endl;

    return 0;
}
// 64 位输出请用 printf("%lld")

HJ30 字符串合并处理

描述
按照指定规则对输入的字符串进行处理。

详细描述:

第一步:将输入的两个字符串str1和str2进行前后合并。如给定字符串 “dec” 和字符串 “fab” , 合并后生成的字符串为 “decfab”

第二步:对合并后的字符串进行排序,要求为:下标为奇数的字符和下标为偶数的字符分别从小到大排序。这里的下标的意思是字符在字符串中的位置。注意排序后在新串中仍需要保持原来的奇偶性。例如刚刚得到的字符串“decfab”,分别对下标为偶数的字符’d’、‘c’、‘a’和下标为奇数的字符’e’、‘f’、'b’进行排序(生成 ‘a’、‘c’、‘d’ 和 ‘b’ 、‘e’ 、‘f’),再依次分别放回原串中的偶数位和奇数位,新字符串变为“abcedf”

第三步:对排序后的字符串中的’0’‘9’、‘A’‘F’和’a’~'f’字符,需要进行转换操作。
转换规则如下:
对以上需要进行转换的字符所代表的十六进制用二进制表示并倒序,然后再转换成对应的十六进制大写字符(注:字符 a~f 的十六进制对应十进制的10~15,大写同理)。
如字符 ‘4’,其二进制为 0100 ,则翻转后为 0010 ,也就是 2 。转换后的字符为 ‘2’。
如字符 ‘7’,其二进制为 0111 ,则翻转后为 1110 ,对应的十进制是14,转换为十六进制的大写字母为 ‘E’。
如字符 ‘C’,代表的十进制是 12 ,其二进制为 1100 ,则翻转后为 0011,也就是3。转换后的字符是 ‘3’。
根据这个转换规则,由第二步生成的字符串 “abcedf” 转换后会生成字符串 “5D37BF”。

输入描述:
样例输入两个字符串,用空格隔开。

输出描述:
输出转化后的结果。

代码 1:

#include <algorithm>
#include <cctype>
#include <iostream>
#include <vector>
using namespace std;

int main() {
    string str1, str2;
    cin >> str1 >> str2;

    // 第一步:将输入的两个字符串str1和str2进行前后合并
    string out = str1 + str2;
    // 第二步:对合并后的字符串进行排序,
    // 要求为:下标为奇数的字符和下标为偶数的字符分别从小到大排序
    vector<char> odd, even;
    for (int i = 0; i < out.length(); i++) {
        if (i % 2)
            odd.push_back(out[i]);
        else
            even.push_back(out[i]);
    }
    sort(odd.begin(), odd.end());
    sort(even.begin(), even.end());
    int odd_idx = 0, even_idx = 0;
    for (int i = 0; i < out.length(); i++) {
        if (i % 2)
            out[i] = odd[odd_idx++];
        else
            out[i] = even[even_idx++];
    }
    // 第三步:对排序后的字符串中的'0'~'9'、'A'~'F'和'a'~'f'字符,需要进行转换操作
    const string trans = "084C2A6E195D3B7F";
    for (char& c : out) {
        if (isdigit(c))
            c = trans[c - '0'];
        else if (c >= 'A' && c <= 'F')
            c = trans[c - 'A' + 10];
        else if (c >= 'a' && c <= 'f')
            c = trans[c - 'a' + 10];
    }
    cout << out << endl;
    return 0;
}
// 64 位输出请用 printf("%lld")

代码 2:

#include <algorithm>
#include <cctype>
#include <iostream>
#include <vector>
#include <cmath>
using namespace std;

int reverseDec(int& num) {
    vector<int> numBin;
    while (num > 1) {
        numBin.push_back(num % 2);
        num /= 2;
    }
    numBin.push_back(num);
    while (numBin.size() < 4) {
        numBin.push_back(0);
    }
    int retVal = 0;
    for (int i = 0; i < numBin.size(); i++) {
        retVal += numBin[numBin.size() - 1 - i] * pow(2, i);
    }
    return retVal;
}

void transform(char& c) {
    int numDec;
    if (isdigit(c)) {
        numDec = c - '0';
    } else if (c >= 'A' && c <= 'F') {
        numDec = 10 + c - 'A';
    } else if (c >= 'a' && c <= 'f') {
        numDec = 10 + c - 'a';
    }
    numDec = reverseDec(numDec);
    if (numDec <= 9) {
        c = '0' + numDec;
    } else {
        c = numDec - 10 + 'A';
    }
}

int main() {
    string str1, str2;
    cin >> str1 >> str2;

    // 第一步:将输入的两个字符串str1和str2进行前后合并
    string out = str1 + str2;
    // 第二步:对合并后的字符串进行排序,
    // 要求为:下标为奇数的字符和下标为偶数的字符分别从小到大排序
    vector<char> odd, even;
    for (int i = 0; i < out.length(); i++) {
        if (i % 2)
            odd.push_back(out[i]);
        else
            even.push_back(out[i]);
    }
    sort(odd.begin(), odd.end());
    sort(even.begin(), even.end());
    int odd_idx = 0, even_idx = 0;
    for (int i = 0; i < out.length(); i++) {
        if (i % 2)
            out[i] = odd[odd_idx++];
        else
            out[i] = even[even_idx++];
    }
    // 第三步:对排序后的字符串中的'0'~'9'、'A'~'F'和'a'~'f'字符,需要进行转换操作
    const string trans = "084C2A6E195D3B7F";
    for (char& c : out) {
        if (isdigit(c) || c >= 'A' && c <= 'F' || c >= 'a' && c <= 'f')
            transform(c);
    }
    cout << out << endl;
    return 0;
}
// 64 位输出请用 printf("%lld")

HJ31 单词倒排

描述
对字符串中的所有单词进行倒排。

说明:

1、构成单词的字符只有26个大写或小写英文字母;

2、非构成单词的字符均视为单词间隔符;

3、要求倒排后的单词间隔符以一个空格表示;如果原字符串中相邻单词间有多个间隔符时,倒排转换后也只允许出现一个空格间隔符;

4、每个单词最长20个字母;

输入描述:
输入一行,表示用来倒排的句子

输出描述:
输出句子的倒排结果

代码:

#include <cctype>
#include <iostream>
#include <ostream>
#include <sstream>
#include <vector>
using namespace std;

int main()
{
    string input;
    getline(cin, input);
    for (char& c : input)
        if (!isalpha(c))
            c = ' ';
    stringstream ss(input);
    string word;
    vector<string> words;
    while (ss >> word)
        words.push_back(word);
    for (int i = words.size() - 1; i > 0; i--)
        cout << words[i] << " ";
    cout << words[0] << endl;

    return 0;
}
// 64 位输出请用 printf("%lld")

HJ32 密码截取

实质:最长回文子串

算法一:暴力

#include <iostream>
using namespace std;

bool isPalindrome(string& s) {
    return s == string(s.rbegin(), s.rend());
}

int main() {
    string s;
    cin >> s;

    int n = s.length(), maxLen = 0;
    for (int i = 0; i < n; i++)
        for (int len = 1; len <= n - i; len++) {
            string temp = s.substr(i, len);
            if (isPalindrome(temp) && temp.size() > maxLen)
                maxLen = temp.size();
        }
    cout << maxLen << endl;

    return 0;
}
// 64 位输出请用 printf("%lld")

算法二:动态规划

代码:

#include <iostream>
#include <vector>
using namespace std;

int main() {
    string s;
    cin >> s;
    int n = s.size(), maxLen = 1, begin = 0;
    // 状态矩阵
    vector<vector<int>> dp(n, vector<int>(n, false));
    // dp[i][j] 表示 s[i...j] 是否是回文串
    // 初始化:所有长度为 1 的子串都是回文串
    for (int i = 0; i < n; i++)
        dp[i][i] = true;
    // 状态转移
    for (int len = 2; len <= n; len++) // 枚举子串长度
        for (int i = 0; i < n; i++) {  // 枚举左边界
            int j = i + len - 1; // 计算右边界
            if (j >= n)          // 右边界越界
                break;
            if (s[i] != s[j])
                dp[i][j] = false;
            else {
                if (j - i <= 2)
                    dp[i][j] = true;
                else
                    dp[i][j] = dp[i + 1][j - 1];
            }
            if (dp[i][j] == true && j - i + 1 > maxLen) {
                maxLen = j - i + 1;
                begin = i;
            }
        }
    cout<<maxLen<<endl;

    return 0;
}
// 64 位输出请用 printf("%lld")

算法三:Manacher 算法

#include <iostream>
#include <vector>
using namespace std;

// 辅函数 - 以s [left...right] 为起点,计算回文半径(可拓展的步数)
int expand(string s, int left, int right) {
    while (left >= 0 && right < s.size() && s[left] == s[right]) {
        left--;
        right++;
    }
    // 由于while循环退出后left和right各多走了一步,所以在返回的总长度时要减去2
    return (right - left - 2) / 2;
}
// 辅函数 - 对原始字符串 s 进行预处理(添加分隔符)
string addBoundaries(string s, char divide) {
    if (s.empty())
        return "";
    string t;
    for (char& c : s) {
        t += divide;
        t += c;
    }
    t += divide;
    return t;
}
// Manacher 算法
string manacher(string s) {
    // 特判
    if (s.empty() || s.size() < 2)
        return s;
    // 对原始字符串 s 做处理,添加分隔符(例如:将 abc 变成 #a#b#c#)
    string str = addBoundaries(s, '#');
    int n = str.size();
    // right 表示目前计算出的最右端范围,right 和左边都是已探测过的
    int right = 0;
    // center 表示最右端位置的中心对称点
    int center = 0;
    int start = 0, maxLen = 0;
    // p 数组记录所有已探测过的回文半径,后面我们再计算 i 时,根据 p[i_mirror] 计算 i
    vector<int> p(n, 0);
    // 从左到右遍历处理过的字符串,求每个字符的回文半径
    for (int i = 0; i < n; ++i) {
        // 根据i和right的位置分为两种情况:
        // 1. i <= right,利用已知的信息来计算 i
        // 2. i > right,说明 i 的位置时未探测过的,只能用中心探测法
        if (right >= i) {
            // 这句是关键,不用再像中心探测那样,一点点的往左/右扩散,根据已知信息
            // 减少不必要的探测,必须选择两者中的较小者作为左右探测起点
            int minArmLen = min(right - i, p[2 * center - i]);
            p[i] = expand(str, i - minArmLen, i + minArmLen);
        } else {
            // i 落在 right 右边,是没被探测过的,只能用中心探测法
            p[i] = expand(str, i, i);
        }
        // 大于right,说明可以更新最右端范围了,同时更新 center
        if (i + p[i] > right) {
            center = i;
            right = i + p[i];
        }
        // 找到了一个更长的回文半径,更新原始字符串的 start 位置
        if (p[i] > maxLen) {
            maxLen = p[i];
            start = (i - p[i]) / 2;
        }
    }
    // 根据 start 和 maxLen ,从原始字符串中截取一段返回
    return s.substr(start, maxLen);
}


int main() {
    string s;
    cin >> s;
    cout << manacher(s).size() << endl;

    return 0;
}
// 64 位输出请用 printf("%lld")

HJ33 整数与IP地址间的转换

描述
原理:ip地址的每段可以看成是一个0-255的整数,把每段拆分成一个二进制形式组合起来,然后把这个二进制数转变成
一个长整数。
举例:一个ip地址为10.0.3.193
每段数字 相对应的二进制数
10 00001010
0 00000000
3 00000011
193 11000001

组合起来即为:00001010 00000000 00000011 11000001,转换为10进制数就是:167773121,即该IP地址转换后的数字就是它了。

数据范围:保证输入的是合法的 IP 序列

输入描述:
输入
1 输入IP地址
2 输入10进制型的IP地址

输出描述:
输出
1 输出转换成10进制的IP地址
2 输出转换后的IP地址

代码:

#include <iostream>
using namespace std;

int main()
{
    long long a, b, c, d, num;
    scanf("%lld.%lld.%lld.%lld%lld", &a, &b, &c, &d, &num);
    cout << (a << 24) + (b << 16) + (c << 8) + d << endl;

    cout << (num >> 24) << ".";
    num -= (num >> 24 << 24);
    cout << (num >> 16) << ".";
    num -= (num >> 16 << 16);
    cout << (num >> 8) << ".";
    num -= (num >> 8 << 8);
    cout << num << endl;

    return 0;
}
// 64 位输出请用 printf("%lld")

HJ34 图片整理

描述
Lily上课时使用字母数字图片教小朋友们学习英语单词,每次都需要把这些图片按照大小(ASCII码值从小到大)排列收好。请大家给Lily帮忙,通过代码解决。
Lily使用的图片使用字符"A"到"Z"、“a"到"z”、"0"到"9"表示。

输入描述:
一行,一个字符串,字符串中的每个字符表示一张Lily使用的图片。

输出描述:
Lily的所有图片按照从小到大的顺序输出

代码:

#include <algorithm>
#include <iostream>
#include <memory>
using namespace std;

int main() {
    string s;
    cin >> s;
    sort(s.begin(), s.end());
    cout << s;
    return 0;
}
// 64 位输出请用 printf("%lld")

HJ35 蛇形矩阵

描述
蛇形矩阵是由1开始的自然数依次排列成的一个矩阵上三角形。

例如,当输入5时,应该输出的三角形为:

1 3 6 10 15

2 5 9 14

4 8 13

7 12

11

输入描述:
输入正整数N(N不大于100)

输出描述:
输出一个N行的蛇形矩阵。

代码:

#include <iostream>
#include <vector>
using namespace std;

int main() {
    int n;
    cin >> n;

    int num = 1;
    vector<vector<int>> grid(n, vector<int>(n, 0));
    for (int i = 0; i < n; i++) {
        int j = i, k = 0;
        while (j >= 0) {
            grid[j][k] = num;
            num++;
            j--;
            k++;
        }
    }
    // 遍历
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++)
            if (grid[i][j])
                cout << grid[i][j] << " ";
        cout << endl;
    }
    return 0;
}
// 64 位输出请用 printf("%lld")

HJ36 字符串加密

描述
有一种技巧可以对数据进行加密,它使用一个单词作为它的密匙。下面是它的工作原理:首先,选择一个单词作为密匙,如TRAILBLAZERS。如果单词中包含有重复的字母,只保留第1个,将所得结果作为新字母表开头,并将新建立的字母表中未出现的字母按照正常字母表顺序加入新字母表。如下所示:
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z

T R A I L B Z E S C D F G H J K M N O P Q U V W X Y (实际需建立小写字母的字母表,此字母表仅为方便演示)

上面其他用字母表中剩余的字母填充完整。在对信息进行加密时,信息中的每个字母被固定于顶上那行,并用下面那行的对应字母一一取代原文的字母(字母字符的大小写状态应该保留)。因此,使用这个密匙, Attack AT DAWN (黎明时攻击)就会被加密为Tpptad TP ITVH。

请实现下述接口,通过指定的密匙和明文得到密文。

输入描述:
先输入key和要加密的字符串

输出描述:
返回加密后的字符串

代码:

#include <iostream>
#include <set>
#include <vector>
using namespace std;

int main() {
    string key;
    cin >> key;
    set<char> keySet;
    vector<int> keyHash;
    for (char& c : key) {
        if (!keySet.count(c)) {
            keyHash.push_back(c - 'a');
            keySet.insert(c);
        }
    }
    for (int i = 0; i < 26; i++) {
        char ch = i + 'a';
        if (!keySet.count(ch))
            keyHash.push_back(i);
    }

    string input;
    cin >> input;
    string ans;
    for (char& c : input) {
        char out = keyHash[c - 'a'] + 'a';
        ans.push_back(out);
    }
    cout << ans << endl;
    return 0;
}
// 64 位输出请用 printf("%lld")

HJ37 统计每个月兔子的总数

描述
有一种兔子,从出生后第3个月起每个月都生一只兔子,小兔子长到第三个月后每个月又生一只兔子。
例子:假设一只兔子第3个月出生,那么它第5个月开始会每个月生一只兔子。
一月的时候有一只兔子,假如兔子都不死,问第n个月的兔子总数为多少?

输入描述:
输入一个int型整数表示第n个月

输出描述:
输出对应的兔子总数

代码:

#include <iostream>
using namespace std;

int rabbit_sum(int n) {
    if (n == 1 || n == 2)
        return 1;
    return rabbit_sum(n - 1) + rabbit_sum(n - 2);
}

int main() {
    int n;
    cin >> n;
    cout << rabbit_sum(n) << endl;
    return 0;
}
// 64 位输出请用 printf("%lld")

HJ38 求小球落地5次后所经历的路程和第5次反弹的高度

描述
假设一个球从任意高度自由落下,每次落地后反跳回原高度的一半; 再落下, 求它在第5次落地时,共经历多少米?第5次反弹多高?

输入描述:
输入起始高度,int型

输出描述:
分别输出第5次落地时,共经过多少米以及第5次反弹多高。
注意:你可以认为你输出保留六位或以上小数的结果可以通过此题。

代码:

#include <cstdio>
#include <iostream>
using namespace std;

int main() {
    int n;
    cin >> n;
    double sum = n;
    double height = n;
    for (int i = 1; i <= 4; i++) {
        height /= 2;
        sum += 2 * height;
    }
    printf("%.6lf\n%.6lf\n", sum, height / 2);
    return 0;
}
// 64 位输出请用 printf("%lld")

HJ39 判断两个IP是否属于同一子网

描述
IP地址是由4个0-255之间的整数构成的,用"."符号相连。
二进制的IP地址格式有32位,例如:10000011,01101011,00000011,00011000;每八位用十进制表示就是131.107.3.24
子网掩码是用来判断任意两台计算机的IP地址是否属于同一子网络的根据。
子网掩码与IP地址结构相同,是32位二进制数,由1和0组成,且1和0分别连续,其中网络号部分全为“1”和主机号部分全为“0”。
你可以简单的认为子网掩码是一串连续的1和一串连续的0拼接而成的32位二进制数,左边部分都是1,右边部分都是0。
利用子网掩码可以判断两台主机是否在同一子网中。
若两台主机的IP地址分别与它们的子网掩码进行逻辑“与”运算(按位与/AND)后的结果相同,则说明这两台主机在同一子网中。

输入描述:
3行输入,第1行是输入子网掩码、第2,3行是输入两个ip地址
题目的示例中给出了三组数据,但是在实际提交时,你的程序可以只处理一组数据(3行)。

输出描述:
若IP地址或子网掩码格式非法则输出1,若IP1与IP2属于同一子网络输出0,若IP1与IP2不属于同一子网络输出2

代码:

#include <iostream>
#include <sstream>
#include <vector>
using namespace std;

bool judge_ip(const string& ip) {
    int j = 0;
    stringstream ss(ip);
    string seg;
    while (getline(ss, seg, '.'))
        if (++j > 4 || seg.empty() || stoi(seg) > 255 || stoi(seg) < 0)
            return false;
    return j == 4;
}

bool is_mask(const string& ip) {
    stringstream ss(ip);
    string seg;
    unsigned int b = 0;
    while (getline(ss, seg, '.'))
        b = (b << 8) + stoi(seg);

    if (b == 0 || ~b == 0) {
        // 二进制下全是1或者全是0均为非法子网掩码
        return false;
    }
    b = ~b + 1;
    if ((b & (b - 1)) == 0)
        return true;
    return false;
}

vector<int> ipToVector(const string& ip) {
    stringstream ss(ip);
    string seg;
    vector<int> res;
    while (getline(ss, seg, '.'))
        res.push_back(stoi(seg));
    return res;
}

int subNetwork(const string& mask, const string& ip1, const string& ip2) {
    if (!judge_ip(mask) || !judge_ip(ip1) || !judge_ip(ip2) || !is_mask(mask))
        return 1;

    vector<int> maskVec = ipToVector(mask);
    vector<int> ip1Vec = ipToVector(ip1);
    vector<int> ip2Vec = ipToVector(ip2);
    for (int i = 0; i < 3; i++) {
        int f1 = maskVec[i] & ip1Vec[i];
        int f2 = maskVec[i] & ip2Vec[i];
        if (f1 != f2)
            return 2;
    }
    return 0;
}

int main()
{
    string mask, ip1, ip2;
    while (cin >> mask >> ip1 >> ip2)
        cout << subNetwork(mask, ip1, ip2) << endl;

    return 0;
}
// 64 位输出请用 printf("%lld")

HJ40 统计字符

描述
输入一行字符,分别统计出包含英文字母、空格、数字和其它字符的个数。

输入描述:
输入一行字符串,可以有空格

输出描述:
统计其中英文字符,空格字符,数字字符,其他字符的个数

代码:

#include <cctype>
#include <iostream>
using namespace std;

int main() {
    string input;
    getline(cin, input);
    int alpha = 0, space = 0, digit = 0, other = 0;
    for (char& c : input) {
        if (isalpha(c))
            alpha++;
        else if (isdigit(c))
            digit++;
        else if (c == ' ')
            space++;
        else other++;
    }
    cout << alpha << endl << space << endl << digit << endl << other << endl;
    return 0;
}
// 64 位输出请用 printf("%lld")

* HJ41 称砝码

描述
现有n种砝码,重量互不相等,分别为 m1,m2,m3…mn ;
每种砝码对应的数量为 x1,x2,x3…xn 。现在要用这些砝码去称物体的重量(放在同一侧),问能称出多少种不同的重量。

注:称重重量包括 0

输入描述:
对于每组测试数据:
第一行:n — 砝码的种数(范围[1,10])
第二行:m1 m2 m3 … mn — 每种砝码的重量(范围[1,2000])
第三行:x1 x2 x3 … xn — 每种砝码对应的数量(范围[1,10])

输出描述:
利用给定的砝码可以称出的不同的重量数

代码 1:

#include <iostream>
#include <unordered_set>
#include <vector>
using namespace std;

int main() {
    int n;
    cin >> n;
    vector<int> weight(n), num(n);
    for (int i = 0; i < n; i++)
        cin >> weight[i];
    for (int i = 0; i < n; i++)
        cin >> num[i];

    unordered_set<int> s; // 集合用于去重
    s.insert(0); // 0也是一种
    for (int i = 0; i < n; i++) { // 对于每一种砝码
        for (int j = 1; j <= num[i]; j++) { // 用完之前数量之前
            unordered_set<int> temp(s);
            for (auto iter = temp.begin(); iter != temp.end(); iter++)
                s.insert(*iter + weight[i]);
        }
    }
    cout << s.size() << endl;
    return 0;
}
// 64 位输出请用 printf("%lld")

代码 2:

#include <iostream>
#include <unordered_set>
#include <vector>
using namespace std;

int main() {
    int n;
    cin >> n;
    int max_weight = 0;
    vector<int> weight(n), num(n);
    for (int i = 0; i < n; i++)
        cin >> weight[i];
    for (int i = 0; i < n; i++) {
        cin >> num[i];
        max_weight += num[i] * weight[i];
    }

    // unordered_set<int> s;
    // s.insert(0);
    // for (int i = 0; i < n; i++)
    //     for (int j = 1; j <= num[i]; j++) {
    //         unordered_set<int> temp(s);
    //         for (auto it = temp.begin(); it != temp.end(); it++)
    //             s.insert(*it + weight[i]);
    //     }
    // cout << s.size() << endl;

    // dp[i]: 能否称出质量为 i 的砝码
    vector<bool> dp(max_weight + 1, false);
    // 初始化
    dp[0] = true;
    for (int i = 0; i < n; i++)
        for (int j = 1; j <= num[i]; j++)
            for (int k = max_weight; k >= weight[i]; k--)
                if (dp[k - weight[i]] == true)
                    dp[k] = true;

    int count = 0;
    for (int i = 0; i <= max_weight; i++)
        if (dp[i] == true)
            count++;

    cout << count << endl;
    return 0;
}
// 64 位输出请用 printf("%lld")

* HJ42 学英语

描述
Jessi初学英语,为了快速读出一串数字,编写程序将数字转换成英文:

具体规则如下:
1.在英语读法中三位数字看成一整体,后面再加一个计数单位。从最右边往左数,三位一单位,例如12,345 等
2.每三位数后记得带上计数单位 分别是thousand, million, billion.
3.公式:百万以下千以上的数 X thousand X, 10亿以下百万以上的数:X million X thousand X, 10 亿以上的数:X billion X million X thousand X. 每个X分别代表三位数或两位数或一位数。
4.在英式英语中百位数和十位数之间要加and,美式英语中则会省略,我们这个题目采用加上and,百分位为零的话,这道题目我们省略and

下面再看几个数字例句:
22: twenty two
100: one hundred
145: one hundred and forty five
1,234: one thousand two hundred and thirty four
8,088: eight thousand (and) eighty eight (注:这个and可加可不加,这个题目我们选择不加)
486,669: four hundred and eighty six thousand six hundred and sixty nine
1,652,510: one million six hundred and fifty two thousand five hundred and ten

说明:
数字为正整数,不考虑小数,转化结果为英文小写;
保证输入的数据合法
关键字提示:and,billion,million,thousand,hundred。

代码 1:

#include <iostream>
#include <vector>
using namespace std;

vector<string> ones = { "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine" };
vector<string> tens = { "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen" };
vector<string> twenties = { "zero", "ten", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety" };
vector<string> hundreds = { "hundred", "thousand", "million", "billion" };
vector<int> ihundreds = { (int)1e2, (int)1e3, (int)1e6, (int)1e9, (int)1e12 };

string itostr(int n) {
    if (n <= 9)
        return ones[n];
    else if (n < 20)
        return tens[n % 10];
    else if (n < 1e2)
        return twenties[n / 10] + (n % 10 ? " " + ones[n % 10] : "");
    else {
        for (int i = 0; i < 4; i++)
            if (n < ihundreds[i + 1])
                return itostr(n / ihundreds[i]) + " "
                       + hundreds[i]
                       + (n % ihundreds[i] ? (i ? " " : " and ")
                          + itostr(n % ihundreds[i]) : "");
    }
    return "";
}

int main() {
    int n;
    cin>>n;
    cout<<itostr(n)<<endl;

    return 0;
}
// 64 位输出请用 printf("%lld")

代码 2:

#include <iostream>
#include <map>
#include <string>
#include <vector>
using namespace std;

    map<int, string> u10 = {
        {1, "one"},
        {2, "two"},
        {3, "three"},
        {4, "four"},
        {5, "five"},
        {6, "six"},
        {7, "seven"},
        {8, "eight"},
        {9, "nine"}
    };
    map<int, string> u20 = {
        {10, "ten"},
        {11, "eleven"},
        {12, "twelve"},
        {13, "thirteen"},
        {14, "fourteen"},
        {15, "fifteen"},
        {16, "sixteen"},
        {17, "seventeen"},
        {18, "eighteen"},
        {19, "nineteen"}
    };
    map<int, string> u100 = {
        {2, "twenty"},
        {3, "thirty"},
        {4, "forty"},
        {5, "fifty"},
        {6, "sixty"},
        {7, "seventy"},
        {8, "eighty"},
        {9, "ninety"}
    };

void getResult(vector<string>& result, int& num) {
    bool hundredSign = false;
    bool tenSign = false;
    if (num >= 100) {
        hundredSign = true;
        result.push_back(u10[num / 100]);
        result.push_back("hundred");
        num %= 100;
    }
    if (num >= 10) {
        tenSign = true;
        if (hundredSign) {
            result.push_back("and");
        }
        if (num <= 19) {
            result.push_back(u20[num]);
            num = 0;
        } else {
            result.push_back(u100[num / 10]);
            num %= 10;
        }
    }
    if (num > 0) {
        if (hundredSign && !tenSign) {
            result.push_back("and");
        }
        result.push_back(u10[num]);
    }
}

int main() {
    long num;
    cin >> num;

    vector<string> result;

    int numMillion = num / 1000000;
    if (numMillion > 0) {
        getResult(result, numMillion);
        result.push_back("million");
    }

    int numThousand = num % 1000000 / 1000;
    if (numThousand > 0) {
        getResult(result, numThousand);
        result.push_back("thousand");
    }

    int numOne = num % 1000000 % 1000;
    if (numOne > 0) {
        getResult(result, numOne);
    }

    for (auto s : result) {
        cout << s << " ";
    }
    cout << endl;

    return 0;
}

* HJ43 迷宫问题

描述
定义一个二维数组 N*M ,如 5 × 5 数组下所示:

int maze[5][5] = {
0, 1, 0, 0, 0,
0, 1, 1, 1, 0,
0, 0, 0, 0, 0,
0, 1, 1, 1, 0,
0, 0, 0, 1, 0,
};

它表示一个迷宫,其中的1表示墙壁,0表示可以走的路,只能横着走或竖着走,不能斜着走,要求编程序找出从左上角到右下角的路线。入口点为[0,0],既第一格是可以走的路。

输入描述:
输入两个整数,分别表示二维数组的行数,列数。再输入相应的数组,其中的1表示墙壁,0表示可以走的路。数据保证有唯一解,不考虑有多解的情况,即迷宫只有一条通道。

输出描述:
左上角到右下角的最短路径,格式如样例所示。

代码:

#include <functional>
#include <iostream>
#include <vector>
using namespace std;

const int dx[] = {0, 0, 1, -1};
const int dy[] = {1, -1, 0, 0};

int main() {
    int n, m;
    cin >> n >> m;
    vector<vector<int>> grid(n, vector<int>(m, 0));
    for (int i = 0; i < n; i++)
        for (int j = 0; j < m; j++)
            cin >> grid[i][j];

    vector<pair<int, int>> res, path;
    function<void(int, int)> dfs = [&](int i, int j) {
        if (i < 0 || i >= n || j < 0 || j >= m)
            return;
        if (grid[i][j])
            return;

        path.push_back(make_pair(i, j)); // 记入路径
        grid[i][j] = 1;
        if (i == n - 1 && j == m - 1) {
            res = path;
            return;
        }
        // 四个方向搜索
        for (int k = 0; k < 4; k++)
            dfs(i + dx[k], j + dy[k]);
        // 回溯
        path.pop_back();
        grid[i][j] = 0;
    };

    dfs(0, 0);
    for (auto& p : res)
        cout << "(" << p.first << "," << p.second << ")" << endl;

    return 0;
}
// 64 位输出请用 printf("%lld")

* HJ44 Sudoku

描述
问题描述:数独(Sudoku)是一款大众喜爱的数字逻辑游戏。玩家需要根据9X9盘面上的已知数字,推算出所有剩余空格的数字,并且满足每一行、每一列、每一个3X3粗线宫内的数字均含1-9,并且不重复。

输入描述:
包含已知数字的9X9盘面数组[空缺位以数字0表示]

输出描述:
完整的9X9盘面数组

代码:

#include <iostream>
using namespace std;

int num[9][9]; // 用于保存9x9盘面
bool flag = false; // flag为true时表示推算完成,结束递归

// 判断当前位置的值是否满足条件
bool check(int n) {
    int h = n / 9; // 行号
    int l = n % 9; // 列号

    // 同一列中不能有重复
    for (int i = 0; i < 9; ++i) {
        if (i != h && num[i][l] == num[h][l]) {
            return false;
        }
    }
    // 同一行中不能有重复
    for (int j = 0; j < 9; ++j) {
        if (j != l && num[h][j] == num[h][l]) {
            return false;
        }
    }
    // 九宫格内不重复
    for (int i = h / 3 * 3; i < h / 3 * 3 + 3; ++i) {
        for (int j = l / 3 * 3; j < l / 3 * 3 + 3; ++j) {
            if ((i != h || j != l) && num[i][j] == num[h][l]) {
                return false;
            }
        }
    }
    return true;
}

void dfs(int n) {
    // 如果已经递归到右下角,输出整个盘面,并置flag为true,结束递归
    if (n == 81) {
        for (int i = 0; i < 9; ++i) {
            for (int j = 0; j < 8; ++j) {
                cout << num[i][j] << ' ';
            }
            cout << num[i][8] << endl;
        }
        flag = true;
        return;
    }
    int h = n / 9; // 行号
    int l = n % 9; // 列号

    // 如果当前位置为0,说明需要推算
    if (num[h][l] == 0) {
        // 枚举1-9的数字,判断哪个满足条件
        for (int i = 1; i <= 9; ++i) {
            num[h][l] = i;
            // 判断当前数字是否满足条件
            if (check(n)) {
                // 如果满足条件继续往下递归
                dfs(n + 1);
                // 如果flag为true表示整个盘面的递归结束了
                if (flag)
                    return;
            }
        }
        // 需要回溯,恢复num[h][l]的值为0
        num[h][l] = 0;
    } else { 
        // 当前位置不为0,往下一格递归
        dfs(n + 1);
    }
}

int main() {
    for (int i = 0; i < 9; ++i) {
        for (int j = 0; j < 9; ++j) {
            cin >> num[i][j];
        }
    }
    dfs(0); // 从左上角开始递归
    return 0;
}
// 64 位输出请用 printf("%lld")

HJ45 名字的漂亮度

描述
给出一个字符串,该字符串仅由小写字母组成,定义这个字符串的“漂亮度”是其所有字母“漂亮度”的总和。
每个字母都有一个“漂亮度”,范围在1到26之间。没有任何两个不同字母拥有相同的“漂亮度”。字母忽略大小写。

给出多个字符串,计算每个字符串最大可能的“漂亮度”。

本题含有多组数据。

输入描述:
第一行一个整数N,接下来N行每行一个字符串

输出描述:
每个字符串可能的最大漂亮程度

代码:

#include <functional>
#include <iostream>
#include <vector>
using namespace std;

int maxBeauty(const string& s) {
    vector<int> cnt(26, 0);
    for (const char& c : s)
        cnt[c - 'a']++;
    sort(cnt.begin(), cnt.end(), greater<>());
    int b = 26, sum = 0;
    for (int i = 0; i < 26; i++) {
        sum += cnt[i] * b;
        b--;
    }
    return sum;
}

int main() {
    int n;
    cin >> n;
    string s;
    for (int i = 0; i < n; i++) {
        cin >> s;
        cout << maxBeauty(s) << endl;
    }
    return 0;
}
// 64 位输出请用 printf("%lld")

HJ46 截取字符串

描述
输入一个字符串和一个整数 k ,截取字符串的前k个字符并输出

输入描述:
1.输入待截取的字符串

2.输入一个正整数k,代表截取的长度

输出描述:
截取后的字符串

代码:

#include <iostream>
using namespace std;

int main() {
    string input;
    cin >> input;
    int k;
    cin >> k;
    cout << input.substr(0, k) << endl;
    return 0;
}
// 64 位输出请用 printf("%lld")

HJ48 从单向链表中删除指定值的节点

描述
输入一个单向链表和一个节点的值,从单向链表中删除等于该值的节点,删除后如果链表中无节点则返回空指针。

链表的值不能重复。

输入描述:
输入一行,有以下4个部分:
1 输入链表结点个数
2 输入头结点的值
3 按照格式插入各个结点
4 输入要删除的结点的值

输出描述:
输出一行
输出删除结点后的序列,每个数后都要加空格

代码:

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int main() {
    int n;
    cin >> n;
    vector<int> arr;
    int x;
    cin >> x;
    arr.push_back(x);
    for (int i = 1; i < n; i++) {
        int num, ins;
        // 在 ins 的后面插入 num
        cin >> num >> ins;
        auto it = find(arr.begin(), arr.end(), ins);
        if (it != arr.end())
            arr.insert(it + 1, num);
        else
            arr.push_back(num);
    }
    int del;
    cin >> del;
    arr.erase(find(arr.begin(), arr.end(), del));
    for (int& x : arr)
        cout << x << " ";
    return 0;
}
// 64 位输出请用 printf("%lld")

** HJ50 四则运算

描述
输入一个表达式(用字符串表示),求这个表达式的值。
保证字符串中的有效字符包括[‘0’-‘9’],‘+’,‘-’, ‘*’,‘/’ ,‘(’, ‘)’,‘[’, ‘]’,‘{’ ,‘}’。且表达式一定合法。

输入描述:
输入一个算术表达式

输出描述:
得到计算结果

代码:

#include <cctype>
#include <iostream>
#include <stack>
using namespace std;

void compute(stack<int>& ns, stack<char>& ops) {
    int num2 = ns.top();
    ns.pop();
    int num1 = ns.top();
    ns.pop();
    char op = ops.top();
    ops.pop();

    int res;
    switch (op) {
        case '+':
            res = num1 + num2;
            break;
        case '-':
            res = num1 - num2;
            break;
        case '*':
            res = num1 * num2;
            break;
        case '/':
            res = num1 / num2;
            break;
    }
    ns.push(res);
}

// 比较运算符优先级
bool priority(char m, char n) {
    if (m == '(') // 括号优先级最高
        return false;
    // 加减法小于乘除法
    else if ((m == '+' || m == '-') && (n == '*' || n == '/'))
        return false;
    return true;
}

int main() {
    string s;
    cin >> s;
    stack<int> ns;
    stack<char> ops;
    ops.push('(');
    s += ')';
    bool flag = false;
    for (int i = 0; i < s.length(); i++) {
        // 遇到左括号
        if (s[i] == '(' || s[i] == '[' || s[i] == '{')
            ops.push('(');
        // 遇到右括号
        else if (s[i] == ')' || s[i] == ']' || s[i] == '}') {
            // 弹出开始计算直到遇到左括号
            while (ops.top() != '(')
                compute(ns, ops);
            // 弹出左括号
            ops.pop();
        }
        // 遇到运算符
        else if (flag) {
            // 当s[i]的优先级小于等于栈顶符号优先级时,对栈顶进行一次计算,直到不符合条件
            while (priority(ops.top(), s[i]))
                compute(ns, ops);
            // 需要将当前运算符加入栈中等待运算
            ops.push(s[i]);
            flag = false;
        }
        // 遇到数字
        else {
            int j = i;
            if (s[j] == '-' || s[j] == '+')
                i++;
            while (isdigit(s[i]))
                i++;
            ns.push(stoi(s.substr(j, i - j)));
            i--;
            // 数字结束,下一次flag为true就是运算符了
            flag = true;
        }
    }
    cout << ns.top() << endl;

    return 0;
}
// 64 位输出请用 printf("%lld")

HJ51 输出单向链表中倒数第k个结点

描述
输入一个单向链表,输出该链表中倒数第k个结点,链表的倒数第1个结点为链表的尾指针。

要求:
(1)正序构建链表;
(2)构建后要忘记链表长度。

输入描述:
输入说明
1 输入链表结点个数
2 输入链表的值
3 输入k的值

输出描述:
输出一个整数

代码:

#include <iostream>
using namespace std;

struct ListNode {
    int m_nKey;
    ListNode* m_pNext;

    ListNode(): m_nKey(0), m_pNext(nullptr) {};
    ListNode(int x): m_nKey(x), m_pNext(nullptr) {};
};

ListNode* FindKthToTail(ListNode* head, int k) {
    ListNode* fast = head;
    ListNode* slow = head;
    while (k--) {
        if (fast)
            fast = fast->m_pNext;
        else
            return nullptr;
    }
    while(fast)
    {
        fast = fast->m_pNext;
        slow = slow->m_pNext;
    }
    return slow;
}

int main()
{
    int n;
    while (cin >> n) {
        // 建立单链表
        ListNode* head = new ListNode(-1);
        ListNode* cur = head;
        for (int i = 0; i < n; i++) {
            int x;
            cin >> x;
            ListNode* nxt = new ListNode(x);
            cur->m_pNext = nxt;
            cur = cur->m_pNext;
        }

        int k;
        cin >> k;

        ListNode* p = FindKthToTail(head->m_pNext, k);
        if (p)
            cout << p->m_nKey << endl;
    }

    return 0;
}
// 64 位输出请用 printf("%lld")

HJ52 计算字符串的编辑距离

描述
Levenshtein 距离,又称编辑距离,指的是两个字符串之间,由一个转换成另一个所需的最少编辑操作次数。许可的编辑操作包括将一个字符替换成另一个字符,插入一个字符,删除一个字符。编辑距离的算法是首先由俄国科学家 Levenshtein 提出的,故又叫 Levenshtein Distance 。

例如:

字符串A: abcdefg

字符串B: abcdef

通过增加或是删掉字符 ”g” 的方式达到目的。这两种方案都需要一次操作。把这个操作所需要的次数定义为两个字符串的距离。

要求:

给定任意两个字符串,写出一个算法计算它们的编辑距离。

输入描述:
每组用例一共2行,为输入的两个字符串

输出描述:
每组用例输出一行,代表字符串的距离

代码:

#include <iostream>
#include <vector>
using namespace std;


int minDistance(string& word1, string& word2) {
    // 特判
    if (word1.empty())
        return word2.size();
    if (word2.empty())
        return word1.size();

    int len1 = word1.size(), len2 = word2.size();
    // 状态矩阵
    // dp[i,j]: word1到位置i为止,和word2到位置j为止,最少需要几步编辑
    vector<vector<int>> dp(len1 + 1, vector<int>(len2 + 1, 0));
    // 初始化
    for (int i = 0; i <= len1; i++)
        dp[i][0] = i;
    for (int j = 0; j <= len2; j++)
        dp[0][j] = j;
    // 状态转移
    for (int i = 1; i <= len1; i++)
        for (int j = 1; j <= len2; j++) {
            // 当第i位和第j位对应的字符相同时,无需操作
            if (word1[i - 1] == word2[j - 1])
                dp[i][j] = dp[i - 1][j - 1];
            // 当二者对应的字符不同时,
            // 修改的消耗是dp[i-1][j-1]+1
            // 插入i位置/删除j位置的消耗是dp[i][j-1]+1,
            // 插入j位置/删除i位置的消耗是dp[i-1][j]+1
            else {
                int op1 = dp[i - 1][j - 1] + 1;
                int op2 = dp[i - 1][j] + 1;
                int op3 = dp[i][j - 1] + 1;
                dp[i][j] = min(op1, min(op2, op3));
            }
        }
    return dp[len1][len2];
}

int main() {
    string s1, s2;
    cin >> s1 >> s2;
    cout << minDistance(s1, s2) << endl;

    return 0;
}
// 64 位输出请用 printf("%lld")

HJ53 杨辉三角的变形

描述

求杨辉三角第n行第一个偶数出现的位置。如果没有偶数,则输出-1。例如输入3,则输出2,输入4则输出3,输入2则输出-1。

输入描述:
输入一个int整数

输出描述:
输出返回的int值

代码:

#include <iostream>
using namespace std;

int main() {
    // 规律:-1, -1, 2, 3, 2, 4, 2, 3, 2, 4...
    int n;
    cin >> n;
    if (n <= 2)
        cout << -1 << endl;
    else {
        int ans[] = {2, 3, 2, 4};
        cout << ans[(n - 3) % 4] << endl;
    }
    return 0;
}
// 64 位输出请用 printf("%lld")

* HJ54 表达式求值

描述
给定一个字符串描述的算术表达式,计算出结果值。

输入字符串长度不超过 100 ,合法的字符包括 ”+, -, *, /, (, )” , ”0-9” 。

输入描述:
输入算术表达式

输出描述:
计算出结果值

代码:

#include <cctype>
#include <iostream>
#include <stack>
using namespace std;

void compute(stack<int>& ns, stack<char>& ops) {
    int num2 = ns.top();
    ns.pop();
    int num1 = ns.top();
    ns.pop();
    char op = ops.top();
    ops.pop();

    int res;
    switch (op) {
        case '+':
            res = num1 + num2;
            break;
        case '-':
            res = num1 - num2;
            break;
        case '*':
            res = num1 * num2;
            break;
        case '/':
            res = num1 / num2;
            break;
    }
    ns.push(res);
}

// 比较运算符优先级
bool priority(char m, char n) {
    if (m == '(') // 括号优先级最高
        return false;
    // 加减法小于乘除法
    else if ((m == '+' || m == '-') && (n == '*' || n == '/'))
        return false;
    return true;
}

int main()
{
    string s;
    cin >> s;
    stack<int> ns;
    stack<char> ops;
    ops.push('(');
    s += ')';
    bool flag = false;
    for (int i = 0; i < s.length(); i++) {
        // 遇到左括号
        if (s[i] == '(' || s[i] == '[' || s[i] == '{')
            ops.push('(');
        // 遇到右括号
        else if (s[i] == ')' || s[i] == ']' || s[i] == '}') {
            // 弹出开始计算直到遇到左括号
            while (ops.top() != '(')
                compute(ns, ops);
            // 弹出左括号
            ops.pop();
        }
        // 遇到运算符
        else if (flag) {
            // 当s[i]的优先级小于等于栈顶符号优先级时,对栈顶进行一次计算,直到不符合条件
            while (priority(ops.top(), s[i]))
                compute(ns, ops);
            // 需要将当前运算符加入栈中等待运算
            ops.push(s[i]);
            flag = false;
        }
        // 遇到数字
        else {
            int j = i;
            if (s[j] == '-' || s[j] == '+')
                i++;
            while (isdigit(s[i]))
                i++;
            ns.push(stoi(s.substr(j, i - j)));
            i--;
            // 数字结束,下一次flag为true就是运算符了
            flag = true;
        }
    }
    cout << ns.top() << endl;

    return 0;
}
// 64 位输出请用 printf("%lld")

HJ55 挑7

描述
输出 1到n之间 的与 7 有关数字的个数。
一个数与7有关是指这个数是 7 的倍数,或者是包含 7 的数字(如 17 ,27 ,37 … 70 ,71 ,72 ,73…)

输入描述:
一个正整数 n 。( n 不大于 30000 )

输出描述:
一个整数,表示1到n之间的与7有关的数字个数。

代码:

#include <iostream>
using namespace std;

bool has7(int x) {
    bool judge = false;
    while (x) {
        if (x % 10 == 7) {
            judge = true;
            break;
        }
        x /= 10;
    }
    return judge;
}

int main() {
    int n;
    cin >> n;
    int count = 0;
    for (int i = 1; i <= n; i++) {
        if (i % 7 == 0 || has7(i))
            count++;
    }
    cout << count << endl;

    return 0;
}
// 64 位输出请用 printf("%lld")

HJ56 完全数计算

描述
完全数(Perfect number),又称完美数或完备数,是一些特殊的自然数。

它所有的真因子(即除了自身以外的约数)的和(即因子函数),恰好等于它本身。

例如:28,它有约数1、2、4、7、14、28,除去它本身28外,其余5个数相加,1+2+4+7+14=28。

输入描述:
输入一个数字n

输出描述:
输出不超过n的完全数的个数

代码:

#include <iostream>
#include <numeric>
#include <vector>
using namespace std;

bool isPrefect(int x) {
    vector<int> v;
    for (int i = 1; i < x; i++)
        if (x % i == 0)
            v.push_back(i);
    return accumulate(v.begin(), v.end(), 0) == x;
}

int main() {
    int n;
    cin >> n;

    int cnt = 0;
    for (int x = 1; x <= n; x++)
        if (isPrefect(x))
            cnt++;
    cout << cnt << endl;

    return 0;
}
// 64 位输出请用 printf("%lld")

HJ57 高精度整数加法

描述
输入两个用字符串 str 表示的整数,求它们所表示的数之和。

输入描述:
输入两个字符串。保证字符串只含有’0’~'9’字符

输出描述:
输出求和后的结果

代码:

#include <algorithm>
#include <any>
#include <iostream>
using namespace std;

int main() {
    string num1, num2;
    cin >> num1 >> num2;

    string ans;
    int i = num1.length() - 1, j = num2.length() - 1;
    int add = 0;
    while (i >= 0 || j >= 0) {
        int d1 = i >= 0 ? num1[i] - '0' : 0;
        int d2 = j >= 0 ? num2[j] - '0' : 0;
        int sum = d1 + d2 + add;
        i--;
        j--;
        ans.push_back(sum % 10 + '0');
        add = sum / 10;
    }
    if (add)
        ans.push_back('1');
    reverse(ans.begin(), ans.end());
    cout << ans << endl;

    return 0;
}
// 64 位输出请用 printf("%lld")

HJ58 输入n个整数,输出其中最小的k个

描述
输入n个整数,找出其中最小的k个整数并按升序输出

本题有多组输入样例

输入描述:
第一行输入两个整数n和k
第二行输入一个整数数组

输出描述:
从小到大输出最小的k个整数,用空格分开。

代码:

#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;

int main() {
    int n, k;
    while (cin >> n >> k) {
        vector<int> v(n);
        for (int i = 0; i < n; i++)
            cin >> v[i];

        sort(v.begin(), v.end());

        for (int i = 0; i < k; i++)
            cout << v[i] << ' ';
    }
    return 0;
}
// 64 位输出请用 printf("%lld")

HJ59 找出字符串中第一个只出现一次的字符

描述
找出字符串中第一个只出现一次的字符

输入描述:
输入一个非空字符串

输出描述:
输出第一个只出现一次的字符,如果不存在输出-1

代码:

#include <iostream>
#include <unordered_map>
using namespace std;

int main() {
    string s;
    cin >> s;
    unordered_map<char, int> cnt;
    for (char& c : s)
        cnt[c]++;

    char ch;
    bool find = false;
    for (char& c : s)
        if (cnt[c] == 1) {
            find = true;
            ch = c;
            break;
        }
    if (find)
        cout << ch << endl;
    else
        cout << -1 << endl;

    return 0;
}
// 64 位输出请用 printf("%lld")

HJ60 查找组成一个偶数最接近的两个素数

描述
任意一个偶数(大于2)都可以由2个素数组成,组成偶数的2个素数有很多种情况,本题目要求输出组成指定偶数的两个素数差值最小的素数对。

输入描述:
输入一个大于2的偶数

输出描述:
从小到大输出两个素数

代码:

#include <iostream>
using namespace std;

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

int main() {
    int n;
    cin >> n;
    for (int i = n / 2; i >= 1; i--)
        if (isPrime(i) && isPrime(n - i)) {
            cout << i << endl << n - i << endl;
            break;
        }
    return 0;
}
// 64 位输出请用 printf("%lld")

* HJ61 放苹果

描述
把m个同样的苹果放在n个同样的盘子里,允许有的盘子空着不放,问共有多少种不同的分法?
注意:如果有7个苹果和3个盘子,(5,1,1)和(1,5,1)被视为是同一种分法。

输入描述:
输入两个int整数

输出描述:
输出结果,int型

代码 1:

#include <iostream>
#include <vector>
using namespace std;

int main() {
    int m, n;
    // m个苹果,n个盘子
    cin >> m >> n;
    // dp[i,j]: i个苹果放进j个盘子的放法
    vector<vector<int>> dp(m + 1, vector<int>(n + 1, 0));
    // 初始化
    for (int i = 1; i <= n; i++) {
        // 0个苹果只有1种分法
        dp[0][i] = 1;
    }
    // 状态转移
    for (int i = 1; i <= m; i++)
        for (int j = 1; j <= n; j++) {
            if (i < j) {
                // 苹果数<盘子数,则等于它前一个盘子时的分法
                dp[i][j] = dp[i][j - 1];
            } else {
                // 1. 假设有一个盘子为空,则问题转化为将i个苹果放在j-1个盘子上
                // 2. 假设所有盘子都装有苹果,则每个盘子上至少有一个苹果,
                // 即最多剩下i-j个苹果,问题转化为将i-j个苹果放到j个盘子上
                dp[i][j] = dp[i][j - 1] + dp[i - j][j];
            }
        }
    cout << dp[m][n] << endl;
    return 0;
}
// 64 位输出请用 printf("%lld")

代码 2:

#include <iostream>
#include <vector>
using namespace std;

int f(int m, int n) {
    if (m < 0 || n < 0)
        return 0;
    if (m == 1 || n == 1)
        return 1;
    return f(m, n - 1) + f(m - n, n);
}

int main() {
    int m, n;
    // m个苹果,n个盘子
    cin >> m >> n;
    cout << f(m, n) << endl;

    return 0;
}
// 64 位输出请用 printf("%lld")

HJ62 查找输入整数二进制中1的个数

描述
输入一个正整数,计算它在二进制下的1的个数。
注意多组输入输出!!!!!!

输入描述:
输入一个整数

输出描述:
计算整数二进制中1的个数

代码:

#include <iostream>
using namespace std;

int bitCount(int x) {
    int count = 0;
    while (x) {
        count += x % 2;
        x /= 2;
    }
    return count;
}

int main()
{
    int n;
    while (cin >> n)
        cout << bitCount(n) << endl;
}
// 64 位输出请用 printf("%lld")

描述
一个 DNA 序列由 A/C/G/T 四个字母的排列组合组成。 G 和 C 的比例(定义为 GC-Ratio )是序列中 G 和 C 两个字母的总的出现次数除以总的字母数目(也就是序列长度)。在基因工程中,这个比例非常重要。因为高的 GC-Ratio 可能是基因的起始点。

给定一个很长的 DNA 序列,以及限定的子串长度 N ,请帮助研究人员在给出的 DNA 序列中从左往右找出 GC-Ratio 最高且长度为 N 的第一个子串。
DNA序列为 ACGT 的子串有: ACG , CG , CGT 等等,但是没有 AGT , CT 等等

输入描述:
输入一个string型基因序列,和int型子串的长度

输出描述:
找出GC比例最高的子串,如果有多个则输出第一个的子串

代码:

#include <iostream>
using namespace std;

int gcCount(string& s) {
    int count = 0;
    for (char& c : s)
        if (c == 'G' || c == 'C')
            count++;
    return count;
}

int main()
{
    string dna;
    cin >> dna;
    int n;
    cin >> n;

    int max_gc = 0;
    string ans;
    for (int i = 0; i <= dna.length() - n; i++) {
        string tmp = dna.substr(i, n);
        int cur_gc = gcCount(tmp);
        if (max_gc < cur_gc) {
            max_gc = cur_gc;
            ans = tmp;
        }
    }
    cout << ans << endl;

    return 0;
}
// 64 位输出请用 printf("%lld")

* HJ64 MP3光标位置

描述
MP3 Player因为屏幕较小,显示歌曲列表的时候每屏只能显示几首歌曲,用户要通过上下键才能浏览所有的歌曲。为了简化处理,假设每屏只能显示4首歌曲,光标初始的位置为第1首歌。

现在要实现通过上下键控制光标移动来浏览歌曲列表,控制逻辑如下:

歌曲总数<=4的时候,不需要翻页,只是挪动光标位置。

光标在第一首歌曲上时,按Up键光标挪到最后一首歌曲;光标在最后一首歌曲时,按Down键光标挪到第一首歌曲。

其他情况下用户按Up键,光标挪到上一首歌曲;用户按Down键,光标挪到下一首歌曲。

  1. 歌曲总数大于4的时候(以一共有10首歌为例):

特殊翻页:屏幕显示的是第一页(即显示第1 – 4首)时,光标在第一首歌曲上,用户按Up键后,屏幕要显示最后一页(即显示第7-10首歌),同时光标放到最后一首歌上。同样的,屏幕显示最后一页时,光标在最后一首歌曲上,用户按Down键,屏幕要显示第一页,光标挪到第一首歌上。

一般翻页:屏幕显示的不是第一页时,光标在当前屏幕显示的第一首歌曲时,用户按Up键后,屏幕从当前歌曲的上一首开始显示,光标也挪到上一首歌曲。光标当前屏幕的最后一首歌时的Down键处理也类似。

其他情况,不用翻页,只是挪动光标就行。

输入描述:
输入说明:
1 输入歌曲数量
2 输入命令 U或者D

输出描述:
输出说明
1 输出当前列表
2 输出当前选中歌曲

代码:

#include <iostream>
using namespace std;

int main()
{
    int n;
    string commands;
    while (cin >> n >> commands) {
        int curSong = 1; // 选中的歌曲
        int pageBegin = 1; // 页面的起始
        int pageEnd = min(4, n); // 页面的末位置
        for (char &c:commands) {
            if (c == 'U') {
                // 向上移动一格
                curSong = (curSong - 1 - 1 + n) % n + 1;
            } else if (c == 'D') {
                // 向下移动一格
                curSong = curSong % n + 1;
            }
            if (curSong < pageBegin) {
                // 如果当前歌曲在窗口前,则将窗口往前移动
                pageBegin = curSong;
                pageEnd = pageBegin + 3;
            } else if (curSong > pageEnd) {
                // 如果当前歌曲在窗口后,则将窗口往后移动
                pageEnd = curSong;
                pageBegin = pageEnd - 3;
            }
        }
        for (int i = pageBegin; i <= pageEnd; i++) {
            // 输出当前页面
            cout << i << ' ';
        }
        cout << endl;
        cout << curSong << endl; // 输出选中的歌曲
    }
    return 0;
}

HJ65 查找两个字符串a,b中的最长公共子串

描述
查找两个字符串a,b中的最长公共子串。若有多个,输出在较短串中最先出现的那个。
注:子串的定义:将一个字符串删去前缀和后缀(也可以不删)形成的字符串。请和“子序列”的概念分开!

输入描述:
输入两个字符串

输出描述:
返回重复出现的字符

代码:

#include <iostream>
#include <vector>
using namespace std;

int main() {
    string s1, s2;
    cin >> s1 >> s2;

    if (s1.size() > s2.size())
        swap(s1, s2);
    int len1 = s1.size(), len2 = s2.size();
    int start = 0, mx = 0; // 记录结果
    // dp[i][j]表示以s1[i]和s2[j]结尾的公共子串的最长长度
    vector<vector<int> > dp(len1 + 1, vector<int>(len2 + 1, 0));
    // 初始化
    for (int i = 0; i <= len1; i++)
        dp[i][0] = 0;
    for (int j = 0; j <= len2; j++)
        dp[0][j] = 0;
    // 状态转移
    for (int i = 1; i <= len1; i++) {
        for (int j = 1; j <= len2; j++) {
            if (s1[i - 1] == s2[j - 1])
                dp[i][j] = dp[i - 1][j - 1] + 1;
            else
                dp[i][j] = 0;
            if (dp[i][j] > mx) {
                mx = dp[i][j];
                start = i - mx;
            } else if (dp[i][j] == mx)
                start = min(start, i - mx);
        }
    }
    cout << s1.substr(start, mx) << endl;

    return 0;
}
// 64 位输出请用 printf("%lld")

HJ66 配置文件恢复

有6条配置命令,它们执行的结果分别是:

在这里插入图片描述

注意:he he不是命令。

为了简化输入,方便用户,以“最短唯一匹配原则”匹配(注:需从首字母开始进行匹配):

1、若只输入一字串,则只匹配一个关键字的命令行。例如输入:r,根据该规则,匹配命令reset,执行结果为:reset what;输入:res,根据该规则,匹配命令reset,执行结果为:reset what;
2、若只输入一字串,但匹配命令有两个关键字,则匹配失败。例如输入:reb,可以找到命令reboot backpalne,但是该命令有两个关键词,所有匹配失败,执行结果为:unknown command

3、若输入两字串,则先匹配第一关键字,如果有匹配,继续匹配第二关键字,如果仍不唯一,匹配失败。
例如输入:r b,找到匹配命令reset board 和 reboot backplane,执行结果为:unknown command。
例如输入:b a,无法确定是命令board add还是backplane abort,匹配失败。
4、若输入两字串,则先匹配第一关键字,如果有匹配,继续匹配第二关键字,如果唯一,匹配成功。例如输入:bo a,确定是命令board add,匹配成功。
5、若输入两字串,第一关键字匹配成功,则匹配第二关键字,若无匹配,失败。例如输入:b addr,无法匹配到相应的命令,所以执行结果为:unknow command。
6、若匹配失败,打印“unknown command”

注意:有多组输入。

输入描述:
多行字符串,每行字符串一条命令

输出描述:
执行结果,每条命令输出一行

代码:

#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
using namespace std;

const vector<vector<string>> orders = {
    {"reset"},
    {"reset", "board"},
    {"board", "add"},
    {"board", "delete"},
    {"reboot", "backplane"},
    {"backplane", "abort"}
};

const vector<string> executes = {
    "reset what",
    "board fault",
    "where to add",
    "no board at all",
    "impossible",
    "install first"
};

const string uc = "unknown command";

int main() {
    string order;
    while (getline(cin, order)) { // 输入只有一字串和二字串
        int space = count(order.begin(), order.end(), ' ');
        if (space == 0) { // 一字串
            if (orders[0][0].substr(0, order.length()) == order)
                cout << executes[0] << endl;
            else
                cout << uc << endl;
        } else { // 二字串
            int space_idx = order.find(' ');
            string word1 = order.substr(0, space_idx);
            string word2 = order.substr(space_idx + 1);
            int macth_cnt = 0; // 匹配个数
            string ans;
            for (int i = 1; i <= 5; i++) {
                if (orders[i][0].substr(0, word1.length()) == word1 &&
                        orders[i][1].substr(0, word2.length()) == word2) {
                    macth_cnt++;
                    ans = executes[i];
                }
            }
            if (macth_cnt == 1)
                cout << ans << endl;
            else // 匹配结果不唯一,匹配失败
                cout << uc << endl;
        }
    }
    return 0;
}
// 64 位输出请用 printf("%lld")

HJ67 24点游戏算法

描述
给出4个1-10的数字,通过加减乘除运算,得到数字为24就算胜利,除法指实数除法运算,运算符仅允许出现在两个数字之间,本题对数字选取顺序无要求,但每个数字仅允许使用一次,且需考虑括号运算
此题允许数字重复,如3 3 4 4为合法输入,此输入一共有两个3,但是每个数字只允许使用一次,则运算过程中两个3都被选取并进行对应的计算操作。

输入描述:
读入4个[1,10]的整数,数字允许重复,测试用例保证无异常数字。

输出描述:
对于每组案例,输出一行表示能否得到24点,能输出true,不能输出false

代码:

#include<iostream>
#include<vector>
using namespace std;

// 暴力
// bool check(vector<double>& nums) {
//     char op[4] = {'+', '-', '*', '/'};
//     sort(nums.begin(), nums.end()); //先按照从小到大排
//     do {
//         for (int i = 0; i < 4; i++) //遍历三个位置的所有可能运算符
//             for (int j = 0; j < 4; j++)
//                 for (int k = 0; k < 4; k++) {
//                     double first = cal(nums[0], nums[1], op[i]); //依次运算
//                     double second = cal(first, nums[2], op[j]);
//                     if (cal(second, nums[3], op[k]) == 24) //判断是否等于24
//                         return true;
//                 }
//     } while (next_permutation(nums.begin(), nums.end())); //依次找到其他排列
//     return false;
// }

// 递归检查能否组成24
bool check(vector<double> nums, double result) {
    if (nums.empty()) {
        // 数组为空,判断等不等于24
        return result == 24;
    }
    // 遍历剩下的数字
    for (int i = 0; i < nums.size(); i++) {
        vector<double> rest(nums);
        rest.erase(rest.begin() + i); // 删去使用的数字
        if (check(rest, result + nums[i])
                || check(rest, result - nums[i])
                || check(rest, result * nums[i])
                || check(rest, result / nums[i]))
            return true;
    }
    return false;
}

int main() {
    vector<double> nums(4);
    for (int i = 0; i < 4; i++)
        cin >> nums[i];

    if (check(nums, 0))
        cout << "true" << endl;
    else
        cout << "false" << endl;
    return 0;
}

// 64 位输出请用 printf("%lld")

HJ68 成绩排序

描述
给定一些同学的信息(名字,成绩)序列,请你将他们的信息按照成绩从高到低或从低到高的排列,相同成绩

都按先录入排列在前的规则处理。

示例:
jack 70
peter 96
Tom 70
smith 67

从高到低 成绩
peter 96
jack 70
Tom 70
smith 67

从低到高

smith 67

jack 70

Tom 70
peter 96

注:0代表从高到低,1代表从低到高

输入描述:
第一行输入要排序的人的个数n,第二行输入一个整数表示排序的方式,之后n行分别输入他们的名字和成绩,以一个空格隔开

输出描述:
按照指定方式输出名字和成绩,名字和成绩之间以一个空格隔开

代码:

#include <iostream>
#include <map>
#include <vector>
using namespace std;

int main() {
    int n;
    int flag;
    cin >> n >> flag;

    map<int, vector<string>> mp;
    for (int i = 0; i < n; i++) {
        string name;
        int score;
        cin >> name >> score;
        mp[score].push_back(name);
    }
    if (flag == 0) { // 从高到低
        for (auto it = mp.rbegin(); it != mp.rend(); ++it) {
            // 逆序遍历
            for (int i = 0; i < it->second.size(); i++)
                cout << it->second[i] << " " << it->first << endl;
        }
    } else { // 从低到高
        for (auto it = mp.begin(); it != mp.end(); ++it) {
            // 顺序遍历
            for (int i = 0; i < it->second.size(); i++)
                cout << it->second[i] << " " << it->first << endl;
        }
    }

    return 0;
}
// 64 位输出请用 printf("%lld")

HJ69 矩阵乘法

描述
如果A是个x行y列的矩阵,B是个y行z列的矩阵,把A和B相乘,其结果将是另一个x行z列的矩阵C。

输入描述:
第一行包含一个正整数x,代表第一个矩阵的行数
第二行包含一个正整数y,代表第一个矩阵的列数和第二个矩阵的行数
第三行包含一个正整数z,代表第二个矩阵的列数
之后x行,每行y个整数,代表第一个矩阵的值
之后y行,每行z个整数,代表第二个矩阵的值

输出描述:
对于每组输入数据,输出x行,每行z个整数,代表两个矩阵相乘的结果

代码:

#include <iostream>
#include <vector>
using namespace std;

int main() {
    int x, y, z;
    cin >> x >> y >> z;
    int r1 = x, c1 = y;
    int r2 = y, c2 = z;
    vector<vector<int>> g1(r1, vector<int>(c1));
    vector<vector<int>> g2(r2, vector<int>(c2));
    for (int i = 0; i < r1; i++)
        for (int j = 0; j < c1; j++)
            cin >> g1[i][j];
    for (int i = 0; i < r2; i++)
        for (int j = 0; j < c2; j++)
            cin >> g2[i][j];
            
    vector<vector<int>> ans(r1, vector<int>(c2));
    for (int i = 0; i < r1; i++) {
        for (int j = 0; j < c2; j++) {
            int sum = 0;
            for (int k = 0; k < y; k++)
                sum += g1[i][k] * g2[k][j];
            ans[i][j] = sum;
            cout<<ans[i][j]<<" ";
        }
        cout<<endl;
    }

    return 0;
}
// 64 位输出请用 printf("%lld")

HJ70 矩阵乘法计算量估算

描述
矩阵乘法的运算量与矩阵乘法的顺序强相关。
例如:

A是一个50×10的矩阵,B是10×20的矩阵,C是20×5的矩阵

计算ABC有两种顺序:((AB)C)或者(A(BC)),前者需要计算15000次乘法,后者只需要3500次。

编写程序计算不同的计算顺序需要进行的乘法次数。

输入描述:
输入多行,先输入要计算乘法的矩阵个数n,每个矩阵的行数,列数,总共2n的数,最后输入要计算的法则
计算的法则为一个字符串,仅由左右括号和大写字母(‘A’~‘Z’)组成,保证括号是匹配的且输入合法!

输出描述:
输出需要进行的乘法次数

代码:

#include <iostream>
#include <stack>
#include <utility>
#include <vector>
using namespace std;

int main() {
    int n;
    cin >> n;
    vector<pair<int, int>> gv;
    for (int i = 0; i < n; i++) {
        int r, c;
        cin >> r >> c;
        gv.push_back(make_pair(r, c));
    }
    string s;
    cin >> s;
    int sum = 0;
    stack<pair<int, int>> gs;
    for (char& c : s) {
        if (c == ')') {
            pair<int, int> g2 = gs.top();
            gs.pop();
            pair<int, int> g1 = gs.top();
            gs.pop();
            int r1 = g1.first, c1 = g1.second;
            int r2 = g2.first, c2 = g2.second;
            if (c1 == r2) {
                sum += r1 * c1 * c2;
                gs.push(make_pair(r1, c2));
            } else if (r1 == c2) {
                sum += r1 * c1 * r2;
                gs.push(make_pair(c1, r2));
            }
        } else if (c != '(') {
            int idx = c - 'A';
            gs.push(gv[idx]);
        }
    }
    cout << sum << endl;
    return 0;
}
// 64 位输出请用 printf("%lld")

HJ71 字符串通配符

描述
问题描述:在计算机中,通配符一种特殊语法,广泛应用于文件搜索、数据库、正则表达式等领域。现要求各位实现字符串通配符的算法。
要求:
实现如下2个通配符:
*:匹配0个或以上的字符(注:能被*和?匹配的字符仅由英文字母和数字0到9组成,下同)
?:匹配1个字符

注意:匹配时不区分大小写。

输入:
通配符表达式;
一组字符串。

输出:
返回不区分大小写的匹配结果,匹配成功输出true,匹配失败输出false

代码:

#include <cctype>
#include <iostream>
#include <vector>
using namespace std;

bool judge (char& c) {
    return (isalpha(c) || isalnum(c) || c == '.');
}

bool match(string p, string s) {
    int plen = p.size();
    int slen = s.size();
    // dp[i,j]: p[0,...,i]与s[0,...,j]是否匹配
    vector<vector<bool>> dp(plen + 1, vector<bool>(slen + 1, false));
    // 初始化
    dp[0][0] = true;
    // 状态转移
    for (int i = 1; i <= plen; i++) {
        dp[i][0] = dp[i - 1][0] && (p[i - 1] == '*'); // 首字符为'*'的情况
        for (int j = 1; j <= slen; j++) {
            if (p[i - 1] == '*') {
                dp[i][j] = dp[i - 1][j] || dp[i][j - 1];
            } else {
                if (tolower(p[i - 1]) == tolower(s[j - 1])) // 要么两字符相等
                    dp[i][j] = dp[i - 1][j - 1];
                if (p[i - 1] == '?' && judge(s[j - 1])) // 要么?通配
                    dp[i][j] = dp[i - 1][j - 1];
            }
        }
    }
    return dp[plen][slen];
}

int main() {
    string p, s;
    cin >> p >> s;
    if (match(p, s)) {
        cout << "true" << endl;
    } else {
        cout << "false" << endl;
    }
    return 0;
}
// 64 位输出请用 printf("%lld")

HJ72 百钱买百鸡问题

描述
公元五世纪,我国古代数学家张丘建在《算经》一书中提出了“百鸡问题”:鸡翁一值钱五,鸡母一值钱三,鸡雏三值钱一。百钱买百鸡,问鸡翁、鸡母、鸡雏各几何?
现要求你打印出所有花一百元买一百只鸡的方式。

输入描述:
输入任何一个整数,即可运行程序。

输出描述:
输出有数行,每行三个整数,分别代表鸡翁,母鸡,鸡雏的数量

代码:

#include <iostream>
using namespace std;

int main() {
    int x;
    cin >> x;
    for (int i = 0; i <= 20; i++)
        for (int j = 0; j <= 25; j++)
            for (int k = 0; k <= 100; k++) {
                if (i + j + k == 100 && 5 * i + 3 * j + k / 3.0 == 100.0)
                    cout << i << " " << j << " " << k << endl;
            }
    return 0;
}
// 64 位输出请用 printf("%lld")

HJ73 计算日期到天数转换

描述
根据输入的日期,计算是这一年的第几天。
保证年份为4位数且日期合法。

输入描述:
输入一行,每行空格分割,分别是年,月,日

输出描述:
输出是这一年的第几天

代码:

#include <iostream>
#include <vector>
using namespace std;

int isLeapYear(int y) {
    return (y % 400 == 0) || (y % 100 != 0 && y % 4 == 0);
}

int trans(int y, int m, int d) {
    const vector<int> days = {
        31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
    };
    int sum = 0;
    for (int i = 0; i < m - 1; i++)
        sum += days[i];
    sum += d;
    if (isLeapYear(y) && m > 2)
        sum++;
    return sum;
}

int main() {
    int year, month, day;
    cin >> year >> month >> day;
    cout << trans(year, month, day) << endl;
    return 0;
}
// 64 位输出请用 printf("%lld")

HJ74 参数解析

描述
在命令行输入如下命令:

xcopy /s c:\ d:\e,

各个参数如下:

参数1:命令字xcopy

参数2:字符串/s

参数3:字符串c:\

参数4: 字符串d:\e

请编写一个参数解析程序,实现将命令行各个参数解析出来。

解析规则:

1.参数分隔符为空格
2.对于用""包含起来的参数,如果中间有空格,不能解析为多个参数。比如在命令行输入xcopy /s “C:\program files” "d:“时,参数仍然是4个,第3个参数应该是字符串C:\program files,而不是C:\program,注意输出参数时,需要将”"去掉,引号不存在嵌套情况。
3.参数不定长

4.输入由用例保证,不会出现不符合要求的输入

输入描述:
输入一行字符串,可以有空格

输出描述:
输出参数个数,分解后的参数,每个参数都独占一行

代码:

#include <iostream>
#include <vector>
using namespace std;

int main() {
    string input;
    getline(cin, input);

    vector<string> parameters;
    string parameter = "";
    bool flag = false; // 记录是否进入引号内
    for (int i = 0; i < input.length(); i++) {
        if (flag) { // 在引号内
            if (input[i] != '\"')
                parameter.push_back(input[i]);
            else
                flag = false;
        } else { // 不在引号内
            if (input[i] == ' ') {
                // 遇到空格,截断
                parameters.push_back(parameter);
                parameter.clear();
            } else if (input[i] == '\"') {
                // 进入引号,设置flag
                flag = true;
            } else { // 其余添加进字符串
                parameter.push_back(input[i]);
            }
        }
    }
    parameters.push_back(parameter);
    cout << parameters.size() << endl;
    for (string& p : parameters)
        cout << p << endl;
        
    return 0;
}
// 64 位输出请用 printf("%lld")

HJ75 公共子串计算

描述
给定两个只包含小写字母的字符串,计算两个字符串的最大公共子串的长度。

注:子串的定义指一个字符串删掉其部分前缀和后缀(也可以不删)后形成的字符串。

输入描述:
输入两个只包含小写字母的字符串

输出描述:
输出一个整数,代表最大公共子串的长度

代码:

#include <iostream>
#include <vector>
using namespace std;

int LCSLength(string& s1, string& s2) {
    int M = s1.length(), N = s2.length();
    vector<vector<int>> dp(M + 1, vector<int>(N + 1, 0));
    int maxLen = 0;
    for (int i = 1; i <= M; i++)
        for (int j = 1; j <= N; j++) {
            if (s1[i - 1] == s2[j - 1])
                dp[i][j] = dp[i - 1][j - 1] + 1;
            else
                dp[i][j] = 0;
            if (dp[i][j] > maxLen)
                maxLen = dp[i][j];
        }
    return maxLen;
}

int main() 
{
    string s1, s2;
    cin >> s1 >> s2;
    cout << LCSLength(s1, s2) << endl;

    return 0;
}
// 64 位输出请用 printf("%lld")

HJ76 尼科彻斯定理

描述
验证尼科彻斯定理,即:任何一个整数m的立方都可以写成m个连续奇数之和。

例如:

1^3=1

2^3=3+5

3^3=7+9+11

4^3=13+15+17+19

输入一个正整数m(m≤100),将m的立方写成m个连续奇数之和的形式输出。

输入描述:
输入一个int整数

输出描述:
输出分解后的string

代码:

#include <iostream>
using namespace std;

int main() {
    int m;
    cin >> m;
    int mid = m * m;
    if (mid % 2 == 1) {
        int begin = mid - m / 2 * 2;
        int end = mid + m / 2 * 2;
        for (int i = begin; i <= end; i += 2) {
            if (i != end)
                cout << i << "+";
            else
                cout << i << endl;
        }
    } else {
        int begin = mid - 1 - (m / 2 - 1) * 2;
        int end = mid + 1 + (m / 2 - 1) * 2;
        for (int i = begin; i <= end; i += 2) {
            if (i != end)
                cout << i << "+";
            else
                cout << i << endl;
        }
    }
    return 0;
}
// 64 位输出请用 printf("%lld")

* HJ77 火车进站

描述
给定一个正整数N代表火车数量,0<N<10,接下来输入火车入站的序列,一共N辆火车,每辆火车以数字1-9编号,火车站只有一个方向进出,同时停靠在火车站的列车中,只有后进站的出站了,先进站的才能出站。
要求输出所有火车出站的方案,以字典序排序输出。

输入描述:
第一行输入一个正整数N(0 < N <= 10),第二行包括N个正整数,范围为1到10。

输出描述:
输出以字典序从小到大排序的火车出站序列号,每个编号以空格隔开,每个输出序列换行,具体见sample。

代码 1:

#include <functional>
#include <iostream>
#include <stack>
#include <vector>
using namespace std;

int main() 
{
    int n;
    cin >> n;
    vector<int> trains(n);
    for (int i = 0; i < n; i++)
        cin >> trains[i];

    vector<vector<int>> res;
    vector<int> seq;
    stack<int> s;
    // 回溯算法
    function<void(int)> dfs = [&](int index) {
        if (index >= n && s.empty()) {
            res.push_back(seq);
            return;
        }
        // 进栈
        if (index < n) {
            s.push(trains[index]);
            dfs(index + 1);
            // 回溯
            s.pop();
        }
        // 出栈
        if (!s.empty()) {
            seq.push_back(s.top());
            s.pop();
            dfs(index);
            // 回溯
            s.push(seq.back());
            seq.pop_back();
        }
    };

    dfs(0);
    sort(res.begin(), res.end());
    for (vector<int>& v : res) {
        for (int& x : v)
            cout << x << " ";
        cout << endl;
    }
    return 0;
}
// 64 位输出请用 printf("%lld")

代码 2:

#include <algorithm>
#include <functional>
#include <iostream>
#include <stack>
#include <vector>
using namespace std;

int main() {
    int n;
    cin >> n;
    vector<int> trains(n);
    for (int i = 0; i < n; i++)
        cin >> trains[i];

    const vector<int> original_seq(trains);

    // 全排列前要先排序
    sort(trains.begin(), trains.end());

    auto check = [&](vector<int>& arr) -> bool {
        stack<int> s;
        int idx = 0;
        for (const int& train : original_seq) {
            s.push(train);
            while (!s.empty() && arr[idx] == s.top()) {
                s.pop();
                idx++;
            }
        }
        return s.empty();
    };

    // 全排列
    do {
        if (check(trains)) {
            for (int& x : trains)
                cout << x << " ";
            cout << endl;
        }
    } while (next_permutation(trains.begin(), trains.end()));

    return 0;
}
// 64 位输出请用 printf("%lld")

HJ80 整型数组合并

描述
题目标题:

将两个整型数组按照升序合并,并且过滤掉重复数组元素。
输出时相邻两数之间没有空格。

输入描述:
输入说明,按下列顺序输入:
1 输入第一个数组的个数
2 输入第一个数组的数值
3 输入第二个数组的个数
4 输入第二个数组的数值

输出描述:
输出合并之后的数组

代码:

#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;

int main() {
    int n;
    vector<int> v;
    cin >> n;
    for (int i = 0; i < n; i++) {
        int x;
        cin >> x;
        v.push_back(x);
    }
    cin >> n;
    for (int i = 0; i < n; i++) {
        int x;
        cin >> x;
        v.push_back(x);
    }

    sort(v.begin(), v.end());
    // 分组循环
    for (int i = 0; i < v.size(); i++) {
        while (i <= v.size() - 1 && v[i] == v[i + 1])
            i++;
        cout << v[i];
    }
    return 0;
}
// 64 位输出请用 printf("%lld")

HJ81 字符串字符匹配

描述
判断短字符串S中的所有字符是否在长字符串T中全部出现。
请注意本题有多组样例输入。

输入描述:
输入两个字符串。第一个为短字符串,第二个为长字符串。两个字符串均由小写字母组成。

输出描述:
如果短字符串的所有字符均在长字符串中出现过,则输出字符串"true"。否则输出字符串"false"。

代码:

#include <iostream>
#include <vector>
using namespace std;

// bool isSubStr(string& s1, string& s2) {
//     int len1 = s1.length(), len2 = s2.length();
//     for (int i = 0; i <= len2 - len1; i++)
//         if (s2.substr(i, len1) == s1)
//             return true;
//     return false;
// }

bool isAllOccurred(const string& s1, const string& s2) {
    vector<bool> dict1(26, false);
    for (const char& c : s1)
        dict1[c - 'a'] = true;
    vector<bool> dict2(26, false);
    for (const char& c : s2)
        dict2[c - 'a'] = true;
    for (int i = 0; i < 26; i++)
        if (dict1[i] && !dict2[i])
            return false;
    return true;
}

int main() {
    string s1, s2;
    cin >> s1 >> s2;
    if (isAllOccurred(s1, s2))
        cout << "true" << endl;
    else
        cout << "false" << endl;
    return 0;
}
// 64 位输出请用 printf("%lld")

** HJ82 将真分数分解为埃及分数

描述
分子为1的分数称为埃及分数。现输入一个真分数(分子比分母小的分数,叫做真分数),请将该分数分解为埃及分数。如:8/11 = 1/2+1/5+1/55+1/110。
注:真分数指分子小于分母的分数,分子和分母有可能gcd不为1!
如有多个解,请输出任意一个。

输入描述:
输入一个真分数,String型

输出描述:
输出分解后的string

代码:

#include <iostream>
using namespace std;

int main() {
    // a/b = 1/(x+1) + 1/(x+1) * (a-y)/b
    // 其中,x = b/a,y = b%a
    long a, b; // 分别是分子分母
    char op; // 除号
    while (cin >> a >> op >> b) {
        while (a != 1) { //直到最后的a为1
            if (b % a == 0) { //先去掉公因子
                b = b / a;
                break;
            }
            //按照公式推算运算
            long x = b / a;
            long y = b % a;
            cout << 1 << op << x + 1 << "+";
            a -= y;
            b *= x + 1;
        }
        cout << 1 << op << b << endl;
    }
    return 0;
}
// 64 位输出请用 printf("%lld")

HJ83 二维数组操作

描述

在这里插入图片描述

输入描述:
输入数据按下列顺序输入:
1 表格的行列值
2 要交换的两个单元格的行列值
3 输入要插入的行的数值
4 输入要插入的列的数值
5 输入要查询的单元格的坐标

输出描述:
输出按下列顺序输出:
1 初始化表格是否成功,若成功则返回0, 否则返回-1
2 输出交换单元格是否成功
3 输出插入行是否成功
4 输出插入列是否成功
5 输出查询单元格数据是否成功

代码:

#include <iostream>
using namespace std;

int main() {
    int row, col; // 表格的行列值
    while (cin >> row >> col) {
        // 初始化表格是否成功,若成功则返回0, 否则返回-1
        if (row > 0 && row <= 9 && col > 0 && col <= 9)
            cout << 0 << endl;
        else
            cout << -1 << endl;
        // 交换坐标
        int x1, y1, x2, y2;
        cin >> x1 >> y1 >> x2 >> y2;
        if (x1 < 0 || x1 >= row || y1 < 0 || y1 >= col
                || x2 < 0 || x2 >= row || y2 < 0 || y2 >= col)
            cout << -1 << endl;
        else
            cout << 0 << endl;
        // 在第x行上方添加一行
        int x;
        cin >> x;
        if (x < 0 || x >= row || row >= 9)
            cout << -1 << endl;
        else
            cout << 0 << endl;
        // 在第 y 列左边添加一列
        int y;
        cin >> y;
        if (y < 0 || y >= col || col >= 9)
            cout << -1 << endl;
        else
            cout << 0 << endl;
        // 查找坐标为 (x,y) 的单元格的值
        cin >> x >> y;
        if (x < 0 || x >= row || y < 0 || y >= col)
            cout << -1 << endl;
        else
            cout << 0 << endl;
    }
    return 0;
}
// 64 位输出请用 printf("%lld")

HJ84 统计大写字母个数

描述
找出给定字符串中大写字符(即’A’-‘Z’)的个数。
字符串中可能包含空格或其他字符。

输入描述:
对于每组样例,输入一行,代表待统计的字符串

输出描述:
输出一个整数,代表字符串中大写字母的个数

代码:

#include <cctype>
#include <iostream>
using namespace std;

int main() {
    string s;
    getline(cin, s);
    int count = 0;
    for (char& c : s)
        if (isupper(c))
            count++;

    cout << count << endl;
    return 0;
}
// 64 位输出请用 printf("%lld")

HJ85 最长回文子串

描述
给定一个仅包含小写字母的字符串,求它的最长回文子串的长度。
所谓回文串,指左右对称的字符串。
所谓子串,指一个字符串删掉其部分前缀和后缀(也可以不删)的字符串

输入描述:
输入一个仅包含小写字母的字符串

输出描述:
返回最长回文子串的长度

代码:

#include <iostream>
using namespace std;

int palindromeLength(string& s, int low, int high) {
    while (low >= 0 && high < s.length() && s[low] == s[high]) {
        low--;
        high++;
    }
    int len = high - low - 1;
    return len;
}

int main() {
    string s;
    cin >> s;

    int maxLen = 1;
    for (int i = 1; i < s.length() - 1; i++) {
        int len1 = palindromeLength(s, i, i);
        int len2 = palindromeLength(s, i, i + 1);
        if (max(len1, len2) > maxLen)
            maxLen = max(len1, len2);
    }
    cout << maxLen << endl;
    return 0;
}
// 64 位输出请用 printf("%lld")

HJ86 求最大连续bit数

描述
求一个int类型数字对应的二进制数字中1的最大连续数,例如3的二进制为00000011,最大连续2个1

输入描述:
输入一个int类型数字

输出描述:
输出转成二进制之后连续1的个数

代码 1:

#include <iostream>
using namespace std;

int main() {
    int n;
    cin >> n;

    int count = 0, max_count = 0;
    while (n) {
        if (n % 2 == 1) // 最后一位为1
            count++;
        else { // 遇到不为1
            max_count = max(max_count, count); // 更新最大值
            count = 0; // 重置
        }
        n /= 2; // 去掉最后一位
    }
    max_count = max(max_count, count); // 最后一次更新最大值
    cout << max_count << endl;

    return 0;
}
// 64 位输出请用 printf("%lld")

代码 2:

#include<iostream>
using namespace std;

int main() {
    int n;
    while (cin >> n) {
        int count = 0;
        for (; n != 0; count++) // 统计能够运算多少次
            n &= n << 1; // 与自己左移一位后比较
        cout << count << endl;
    }
    return 0;
}

// 64 位输出请用 printf("%lld")

HJ87 密码强度等级

描述
密码按如下规则进行计分,并根据不同的得分为密码进行安全等级划分。

一、密码长度:
5 分: 小于等于4 个字符
10 分: 5 到7 字符
25 分: 大于等于8 个字符

二、字母:
0 分: 没有字母
10 分: 密码里的字母全都是小(大)写字母
20 分: 密码里的字母符合”大小写混合“

三、数字:
0 分: 没有数字
10 分: 1 个数字
20 分: 大于1 个数字

四、符号:
0 分: 没有符号
10 分: 1 个符号
25 分: 大于1 个符号

五、奖励(只能选符合最多的那一种奖励):
2 分: 字母和数字
3 分: 字母、数字和符号
5 分: 大小写字母、数字和符号

最后的评分标准:
>= 90: 非常安全
>= 80: 安全(Secure)
>= 70: 非常强
>= 60: 强(Strong)
>= 50: 一般(Average)
>= 25: 弱(Weak)
>= 0: 非常弱(Very_Weak)

对应输出为:

VERY_SECURE
SECURE
VERY_STRONG
STRONG
AVERAGE
WEAK
VERY_WEAK

请根据输入的密码字符串,进行安全评定。

注:
字母:a-z, A-Z
数字:0-9
符号包含如下: (ASCII码表可以在UltraEdit的菜单view->ASCII Table查看)
!"#$%&'()*+,-./ (ASCII码:0x21~0x2F)
:;<=>?@ (ASCII码:0x3A~0x40)
[]^_` (ASCII码:0x5B~0x60)
{|}~ (ASCII码:0x7B~0x7E)

提示:
1 <= 字符串的长度<= 300

输入描述:
输入一个string的密码

输出描述:
输出密码等级

代码:

#include <algorithm>
#include <cctype>
#include <iostream>
using namespace std;

bool issignal(char& c) {
    const string signalStr = "!\"#$%&'()*+,-./[\\]^_`{|}~";
    if (find(signalStr.begin(), signalStr.end(), c) != signalStr.end())
        return true;
    else
        return false;
}

int main() {
    string pwd;
    cin >> pwd;

    int score = 0;
    // 密码长度
    int len = pwd.length();
    if (len <= 4)
        score += 5;
    else if (len < 8)
        score += 10;
    else if (len >= 8)
        score += 25;
    // 统计字母、数字、符号
    int lower = 0, upper = 0, digit = 0, signal  = 0;
    for (char& c : pwd) {
        if (islower(c))
            lower++;
        else if (isupper(c))
            upper++;
        else if (isdigit(c))
            digit++;
        else if (issignal(c))
            signal++;
    }
    // 字母
    if ((lower > 0 && upper == 0) || (lower == 0 && upper > 0))
        score += 10;
    else if (lower > 0 && upper > 0)
        score += 20;

    if (digit == 1)
        score += 10;
    else if (digit > 1)
        score += 20;

    if (signal == 1)
        score += 10;
    else if (signal > 1)
        score += 25;

    int alpha = lower + upper;
    if (lower > 0 && upper > 0 && digit > 0 && signal > 0)
        score += 5;
    else if (alpha > 0 && digit > 0 && signal > 0)
        score += 3;
    else if (alpha > 0 && digit > 0)
        score += 2;

    if (score >= 90)
        cout << "VERY_SECURE" << endl;
    else if (score >= 80)
        cout << "SECURE" << endl;
    else if (score >= 70)
        cout << "VERY_STRONG" << endl;
    else if (score >= 60)
        cout << "STRONG" << endl;
    else if (score >= 50)
        cout << "AVERAGE" << endl;
    else if (score >= 25)
        cout << "WEAK" << endl;
    else if (score >= 0)
        cout << "VERY_WEAK" << endl;
    return 0;
}
// 64 位输出请用 printf("%lld")

* HJ88 扑克牌大小

描述
扑克牌游戏大家应该都比较熟悉了,一副牌由54张组成,含3~A、2各4张,小王1张,大王1张。牌面从小到大用如下字符和字符串表示(其中,小写joker表示小王,大写JOKER表示大王):
3 4 5 6 7 8 9 10 J Q K A 2 joker JOKER
输入两手牌,两手牌之间用"-“连接,每手牌的每张牌以空格分隔,”-"两边没有空格,如:4 4 4 4-joker JOKER。
请比较两手牌大小,输出较大的牌,如果不存在比较关系则输出ERROR。
基本规则:
(1)输入每手牌可能是个子、对子、顺子(连续5张)、三个、炸弹(四个)和对王中的一种,不存在其他情况,由输入保证两手牌都是合法的,顺子已经从小到大排列;
(2)除了炸弹和对王可以和所有牌比较之外,其他类型的牌只能跟相同类型的存在比较关系(如,对子跟对子比较,三个跟三个比较),不考虑拆牌情况(如:将对子拆分成个子);
(3)大小规则跟大家平时了解的常见规则相同,个子、对子、三个比较牌面大小;顺子比较最小牌大小;炸弹大于前面所有的牌,炸弹之间比较牌面大小;对王是最大的牌;

(4)输入的两手牌不会出现相等的情况。

输入描述:
输入两手牌,两手牌之间用"-“连接,每手牌的每张牌以空格分隔,”-"两边没有空格,如 4 4 4 4-joker JOKER。

输出描述:
输出两手牌中较大的那手,不含连接符,扑克牌顺序不变,仍以空格隔开;如果不存在比较关系则输出ERROR。

代码:

#include <algorithm>
#include <iostream>
using namespace std;

int getValue(string& s) {
    if (s == "joker")
        return 14;
    if (s == "JOKER")
        return 15;
    switch (s[0]) {
        case '3':
            return 1;
        case '4':
            return 2;
        case '5':
            return 3;
        case '6':
            return 4;
        case '7':
            return 5;
        case '8':
            return 6;
        case '9':
            return 7;
        case '1':
            return 8; // 用1代替10
        case 'J':
            return 9;
        case 'Q':
            return 10;
        case 'K':
            return 11;
        case 'A':
            return 12;
        case '2':
            return 13;
    }
    return 0;
}

int main() {
    string input;
    getline(cin, input);
    int split_idx = find(input.begin(), input.end(), '-') - input.begin();
    string s1 = input.substr(0, split_idx); // 从'-'处截取成两段
    string s2 = input.substr(split_idx + 1);
    // 如果有王炸直接输出王炸
    if (s1 == "joker JOKER" || s2 == "joker JOKER") {
        cout << "joker JOKER" << endl;
        return 0;
    }
    // 统计字符串中空格的数量
    int space1 = 0, space2 = 0;
    for (char& c : s1)
        if (c == ' ')
            space1++;
    for (char& c : s2)
        if (c == ' ')
            space2++;
    // 输入每手牌可能是个子、对子、顺子(连续5张)、三个、炸弹(四个)和对王中的一种,不存在其他情况
    if (space1 == 3 && space2 == 3) {
        // 都是炸弹
        if (getValue(s1) > getValue(s2)) // 比较炸弹大小
            cout << s1 << endl;
        else
            cout << s2 << endl;
    } else if (space1 == 3) // 字符串其中一个是炸弹,输出炸弹
        cout << s1 << endl;
    else if (space2 == 3)
        cout << s2 << endl;
    else if (space1 == space2) { // 没有炸弹的情况下相同类型才能比较
        if (getValue(s1) > getValue(
                    s2)) // 个子、对子、三个、顺子都是比较第一个大小
            cout << s1 << endl;
        else
            cout << s2 << endl;
    } else // 无法比较
        cout << "ERROR" << endl;

    return 0;
}
// 64 位输出请用 printf("%lld")

* HJ89 24点运算

描述
计算24点是一种扑克牌益智游戏,随机抽出4张扑克牌,通过加(+),减(-),乘(*), 除(/)四种运算法则计算得到整数24,本问题中,扑克牌通过如下字符或者字符串表示,其中,小写joker表示小王,大写JOKER表示大王:

3 4 5 6 7 8 9 10 J Q K A 2 joker JOKER

本程序要求实现:输入4张牌,输出一个算式,算式的结果为24点。

详细说明:

1.运算只考虑加减乘除运算,没有阶乘等特殊运算符号,没有括号,友情提醒,整数除法要当心,是属于整除,比如2/3=0,3/2=1;
2.牌面210对应的权值为210, J、Q、K、A权值分别为为11、12、13、1;
3.输入4张牌为字符串形式,以一个空格隔开,首尾无空格;如果输入的4张牌中包含大小王,则输出字符串“ERROR”,表示无法运算;
4.输出的算式格式为4张牌通过±/四个运算符相连,中间无空格,4张牌出现顺序任意,只要结果正确;
5.输出算式的运算顺序从左至右,不包含括号,如1+2+3
4的结果为24,2 A 9 A不能变为(2+1)*(9-1)=24
6.如果存在多种算式都能计算得出24,只需输出一种即可,如果无法得出24,则输出“NONE”表示无解。
7.因为都是扑克牌,不存在单个牌为0的情况,且没有括号运算,除数(即分母)的数字不可能为0

数据范围:一行由4张牌组成的字符串

输入描述:
输入4张牌为字符串形式,以一个空格隔开,首尾无空格;

输出描述:
输出怎么运算得到24,如果无法得出24,则输出“NONE”表示无解,如果输入的4张牌中包含大小王,则输出字符串“ERROR”,表示无法运算;

代码:

#include <algorithm>
#include <iostream>
#include <unordered_map>
#include <vector>
using namespace std;

unordered_map<string, int> CardtoNum = {{"A", 1}, {"2", 2}, {"3", 3}, {"4", 4}, {"5", 5}, {"6", 6},
    {"7", 7}, {"8", 8}, {"9", 9}, {"10", 10}, {"J", 11}, {"Q", 12}, {"K", 13}
}; //输入的字符映射到数字
unordered_map<int, string> NumtoCard = {{1, "A"}, {2, "2"}, {3, "3"}, {4, "4"}, {5, "5"}, {6, "6"},
    {7, "7"}, {8, "8"}, {9, "9"}, {10, "10"}, {11, "J"}, {12, "Q"}, {13, "K"}
}; //返回的数字映射到字符
const vector<char> Op = {'+', '-', '*', '/'};

int cal(int a, int b, int op) {
    switch (op) {
        case 0:
            return a + b;
        case 1:
            return a - b;
        case 2:
            return a * b;
        case 3:
            return a / b;
    }
    return 0;
}

bool cal24(vector<int>& a, vector<int>& op) {
    int res = cal(a[0], a[1], op[0]);
    for (int i = 1; i < 3; i++)
        res = cal(res, a[i + 1], op[i]);
    return res == 24;
}

void printFormula(vector<int>& nums, vector<int>& op) {
    for (int i = 0; i < 3; i++)
        cout << NumtoCard[nums[i]] << Op[op[i]];
    cout <<  NumtoCard[nums[3]]  << endl;
}

int main() {
    vector<string> s(4);
    for (int i = 0; i < 4; i++)
        cin >> s[i];

    vector<int> nums(4);
    for (int i = 0; i < 4; i++) {
        if (s[i] == "joker" || s[i] == "JOKER") { // 遇到大小王
            cout << "ERROR" << endl;
            return 0;
        }
        nums[i] = CardtoNum[s[i]]; // 字符串转数字
    }

    sort(nums.begin(), nums.end());
    bool flag = false;
    vector<int> op(4);
    do {
        // 枚举三个符号的所有情况
        for (int i = 0; i < 4 && !flag; i++) {
            op[0] = i;
            for (int j = 0; j < 4 && !flag; j++) {
                op[1] = j;
                for (int k = 0; k < 4 && !flag; k++) {
                    op[2] = k;
                    if (cal24(nums, op)) { // 符合条件
                        printFormula(nums, op);
                        flag = true; // 找到了,准备跳出所有循环
                    }
                }
            }
        }
    } while (next_permutation(nums.begin(), nums.end()) && !flag);

    if (!flag)
        cout << "NONE" << endl;

    return 0;
}
// 64 位输出请用 printf("%lld")

HJ90 合法IP

描述
IPV4地址可以用一个32位无符号整数来表示,一般用点分方式来显示,点将IP地址分成4个部分,每个部分为8位,表示成一个无符号整数(因此正号不需要出现),如10.137.17.1,是我们非常熟悉的IP地址,一个IP地址串中没有空格出现(因为要表示成一个32数字)。

现在需要你用程序来判断IP是否合法。

输入描述:
输入一个ip地址,保证不包含空格

输出描述:
返回判断的结果YES or NO

代码:

#include <cctype>
#include <iostream>
#include <vector>
#include <sstream>
using namespace std;

bool judge_ip(string& s) {
    vector<int> addr;
    stringstream ss(s);
    string seg;
    while (getline(ss, seg, '.')) {
        if (seg.empty())
            return false;
        if (seg.length() > 1 && (!isdigit(seg[0]) || seg[0] == '0'))
            return false;
        addr.push_back(stoi(seg));
    }
    if (addr.size() != 4)
        return false;
    for (int& a : addr)
        if (a < 0 || a > 255)
            return false;
    return true;
}

int main() {
    string ip;
    cin >> ip;
    if (judge_ip(ip))
        cout << "YES" << endl;
    else
        cout << "NO" << endl;

    return 0;
}
// 64 位输出请用 printf("%lld")

HJ91 走方格的方案数

描述
请计算n*m的棋盘格子(n为横向的格子数,m为竖向的格子数)从棋盘左上角出发沿着边缘线从左上角走到右下角,总共有多少种走法,要求不能走回头路,即:只能往右和往下走,不能往左和往上走。

注:沿棋盘格之间的边缘线行走

输入描述:
输入两个正整数n和m,用空格隔开。(1≤n,m≤8)

输出描述:
输出一行结果

代码:

#include <iostream>
#include <vector>
using namespace std;

int main() {
    int n, m;
    cin >> n >> m;
    // 状态矩阵
    vector<vector<int>> dp(n + 1, vector<int>(m + 1, 1));
    // 初始化
    for (int i = 0; i <= n; i++)
        dp[i][0] = 1;
    for (int j = 0; j <= m; j++)
        dp[0][j] = 1;
    // 状态转移
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= m; j++) {
            dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
        }
    cout << dp[n][m] << endl;

    return 0;
}
// 64 位输出请用 printf("%lld")

HJ92 在字符串中找出连续最长的数字串

描述
输入一个字符串,返回其最长的数字子串,以及其长度。若有多个最长的数字子串,则将它们全部输出(按原字符串的相对位置)
本题含有多组样例输入。

输入描述:
输入一个字符串。1<=len(字符串)<=200

输出描述:
输出字符串中最长的数字字符串和它的长度,中间用逗号间隔。如果有相同长度的串,则要一块儿输出(中间不要输出空格)。

代码:

#include <cctype>
#include <iostream>
#include <utility>
#include <vector>
using namespace std;

int main() {
    string s;
    while (cin >> s) {
        vector<string> digitStr;
        int maxLen = 0;
        int i = 0;
        while (i < s.length()) {
            if (isdigit(s[i])) {
                int j = i + 1;
                while (isdigit(s[j]) && j < s.length())
                    j++;
                // s[i,j-1] 是一个数字子串
                string d = s.substr(i, j - i);
                digitStr.push_back(d);
                maxLen = max(maxLen, (int)d.length());
                i = j + 1;
            } else {
                i++;
            }

        }
        for (string& d : digitStr)
            if (d.length() == maxLen)
                cout << d;
        cout << "," << maxLen << endl;
    }
    return 0;
}
// 64 位输出请用 printf("%lld")

HJ93 数组分组

描述
输入int型数组,询问该数组能否分成两组,使得两组中各元素加起来的和相等,并且,所有5的倍数必须在其中一个组中,所有3的倍数在另一个组中(不包括5的倍数),不是5的倍数也不是3的倍数能放在任意一组,可以将数组分为空数组,能满足以上条件,输出true;不满足时输出false。

输入描述:
第一行是数据个数,第二行是输入的数据

输出描述:
返回true或者false

代码:

#include <iostream>
#include <numeric>
#include <unordered_set>
#include <vector>
using namespace std;

int main() {
    int n;
    cin >> n;
    vector<int> other;
    int sum5 = 0, sum3 = 0;
    for (int i = 0; i < n; i++) {
        int x;
        cin >> x;
        if (x % 5 == 0)
            sum5 += x;
        else if (x % 3 == 0)
            sum3 += x;
        else
            other.push_back(x);
    }
    // 枚举所有组合的不重复和
    unordered_set<int> s;
    s.insert(0); // 0 代表空数组
    for (int& x : other) {
        unordered_set<int> tmp(s);
        for (auto it : tmp)
            s.insert(it + x);
    }
    bool found = false;
    int sum = accumulate(other.begin(), other.end(), 0);
    for (auto it : s)
        if (it + sum3 == sum5 + sum - it) {
            found = true;
            break;
        }
    cout << (found ? "true" : "false") << endl;
    return 0;
}
// 64 位输出请用 printf("%lld")

HJ94 记票统计

描述
请实现一个计票统计系统。你会收到很多投票,其中有合法的也有不合法的,请统计每个候选人得票的数量以及不合法的票数。
(注:不合法的投票指的是投票的名字不存在n个候选人的名字中!!)

输入描述:
第一行输入候选人的人数n,第二行输入n个候选人的名字(均为大写字母的字符串),第三行输入投票人的人数,第四行输入投票。

输出描述:
按照输入的顺序,每行输出候选人的名字和得票数量(以" : "隔开,注:英文冒号左右两边都有一个空格!),最后一行输出不合法的票数,格式为"Invalid : "+不合法的票数。

代码:

#include <iostream>
#include <set>
#include <unordered_map>
#include <vector>
using namespace std;

int main() {
    int n;
    cin >> n;
    vector<string> list;
    set<string> s;
    for (int i = 0; i < n; i++) {
        string name;
        cin >> name;
        list.push_back(name);
        s.insert(name);
    }
    int m;
    cin >> m;
    int valid = 0;
    unordered_map<string, int> mp;
    for (int i = 0; i < m; i++) {
        string name;
        cin >> name;
        if (s.count(name)) {
            mp[name]++;
            valid++;
        }
    }
    // print
    for (auto& name : list)
        cout << name << " : " << mp[name] << endl;
    cout << "Invalid : " << m - valid << endl;
    
    return 0;
}
// 64 位输出请用 printf("%lld")

HJ95 人民币转换

描述
考试题目和要点:

1、中文大写金额数字前应标明“人民币”字样。中文大写金额数字应用壹、贰、叁、肆、伍、陆、柒、捌、玖、拾、佰、仟、万、亿、元、角、分、零、整等字样填写。

2、中文大写金额数字到“元”为止的,在“元”之后,应写“整字,如532.00应写成“人民币伍佰叁拾贰元整”。在”角“和”分“后面不写”整字。

3、阿拉伯数字中间有“0”时,中文大写要写“零”字,阿拉伯数字中间连续有几个“0”时,中文大写金额中间只写一个“零”字,如6007.14,应写成“人民币陆仟零柒元壹角肆分“。
4、10应写作“拾”,100应写作“壹佰”。例如,1010.00应写作“人民币壹仟零拾元整”,110.00应写作“人民币壹佰拾元整”
5、十万以上的数字接千不用加“零”,例如,30105000.00应写作“人民币叁仟零拾万伍仟元整”

输入描述:
输入一个double数

输出描述:
输出人民币格式

代码:

#include <iostream>
using namespace std;

// 构建个位的字典(数组)
const string gewei[10] = {"零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖"};

// 获取元钱的函数接口,即小数点之前的部分
void Get_Before_Plot(string str) {
    if (str == "0") {
        return;
    }
    for (int i = str.size() - 1, j = 0; i >= 0; i--, j++) {
        // i表示这是数字的第几位,j表示字符串下标
        if (str[j] != '0') { // 将当前位置的数字转为中文
            if (!(str[j] == '1' && i % 4 == 1)) // 10应写作“拾”,而不是“壹零”
                cout << gewei[str[j] - '0'];
        }
        if (i != 0) { // 当前不是个位
            if (i % 8 == 0 && i >= 8) { // 亿位
                cout << "亿";
            }
            if (i % 4 == 0 && i % 8 != 0) { // 万位
                cout << "万";
                if (str[j + 1] == '0') // 如果千位为0
                    cout << "零";
            }
            if (i % 4 == 3 && str[j] != '0') { // 千
                cout << "仟";
                if (str[j + 1] == '0' && str[j + 2] != '0') // 百位为0
                    cout << "零";
            }
            if (i % 4 == 2 && str[j] != '0') { //百
                cout << "佰";
                if (str[j + 1] == '0' && str[j + 2] != '0') // 十位为0
                    cout << "零";
            }
            if (i % 4 == 1 && str[j] != '0') // 十位
                cout << "拾";
        }
    }
    return;
}

// 获取角分零钱的函数接口,即小数点之后的部分
void Get_After_Plot(string str) {
    if (str == "00") {
        cout << "整";
        return;
    }
    if (str[0] > '0') {
        cout << gewei[str[0] - '0'] << "角";
    }
    if (str[1] > '0') {
        cout << gewei[str[1] - '0'] << "分";
    }
    return;
}

int main() {
    string money;
    cin >> money;

    //
    string str1 = money.substr(0, money.find('.'));
    // 获取小数点后的子字符串
    string str2 = money.substr(money.find('.') + 1);
    // 输出人民币
    cout << "人民币";
    // 输出元钱
    Get_Before_Plot(str1);
    if (str1 != "0")
        cout << "元";
    // 输出角分零钱
    Get_After_Plot(str2);
    // 换行
    cout << endl;
}
// 64 位输出请用 printf("%lld")

HJ96 表示数字

描述
将一个字符串中所有的整数前后加上符号“*”,其他字符保持不变。连续的数字视为一个整数。

输入描述:
输入一个字符串。

输出描述:
字符中所有出现的数字前后加上符号“*”,其他字符保持不变。

代码:

#include <cctype>
#include <iostream>
using namespace std;

int main() {
    string input;
    cin >> input;

    bool flag = false;
    for (char& c : input) {
        if (isdigit(c)) {
            if (flag == false) {
                // 进入数字子串
                cout << '*';
                flag = true;
            }
            cout << c;
        } else {
            if (flag == true) {
                // 退出数字子串
                cout << '*';
                flag = false;
            }
            cout << c;
        }
    }
    if (isdigit(input[input.length() - 1]))
        cout << '*';

    return 0;
}
// 64 位输出请用 printf("%lld")

HJ97 记负均正

描述
首先输入要输入的整数个数n,然后输入n个整数。输出为n个整数中负数的个数,和所有正整数的平均值,结果保留一位小数。
0即不是正整数,也不是负数,不计入计算。如果没有正数,则平均值为0。

输入描述:
首先输入一个正整数n,
然后输入n个整数。

输出描述:
输出负数的个数,和所有正整数的平均值。

代码:

#include <cstdio>
#include <iostream>
using namespace std;

int main() {
    int n;
    cin >> n;

    int cnt_neg = 0, sum = 0, cnt_pos = 0;
    for (int i = 0; i < n; i++) {
        int x;
        cin >> x;
        if (x > 0) {
            sum += x;
            cnt_pos++;
        } else if (x < 0)
            cnt_neg++;
    }
    cout << cnt_neg << " ";
    if (cnt_pos) {
        double avg = 1.0 * sum / cnt_pos;
        printf("%.1f\n", avg);
    } else
        cout << "0.0" << endl;

    return 0;
}
// 64 位输出请用 printf("%lld")

HJ98 自动售货系统

链接:https://www.nowcoder.com/practice/cd82dc8a4727404ca5d32fcb487c50bf

代码:

#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
#include<sstream>
using namespace std;

const vector<int>  price = {2, 3, 4, 5, 8, 6}; // 商品价格
int money = 0; //投入的钱

// 通过字符c分割字符串
vector<string> split(string str, const char c) {
    vector<string> res;
    istringstream iss(str); // 字符串流输入
    string temp = "";
    while (getline(iss, temp, c)) // 根据流输入分割
        res.push_back(temp);
    return res;
}

// 初始化函数
void init(vector<int>& a, vector<int>& b, string& s) {
    money = 0; // 初始化投入的钱
    s = s.substr(2, s.length() - 2); // 去掉前面的r和空格
    a[0] = a[1] = a[2] = a[3] = a[4] = a[5] = 0;
    b[0] = b[1] = b[2] = b[3] = 0;
    int i = 0;
    // 判别是前面部分商品价格还是后面部分零钱盒
    bool flag = false;
    for (auto c : s) {
        if (isdigit(c) && !flag) // 数字且是价格
            a[i] = a[i] * 10 + (c - ' 0'); // 根据字符计算数字
        else if (isdigit(c) && flag) //数字且是零钱
            b[i] = b[i] * 10 + (c - '0'); // 根据字符计算数字
        else if (c == ' ') { // 遇到空格换成零钱
            flag = true;
            i = 0;
        } else if (c == '-') // 遇到-后移一位商品或零钱
            i++;
    }
    cout << "S001:Initialization is successful" << endl;
}

// 投币函数
void pay(vector<int>& a, vector<int>& b, string& s) {
    int num = 0;
    for (auto& c : s)
        if (isdigit(c)) // 只计算数字部分
            num = num * 10 + (c - '0'); // 一次只投一张
    if (num == 1 || num == 2 || num == 5 || num == 10) { // 投入合法的币种
        if (num > 2 && num > (b[0] + b[1] * 2)) {
            // 存钱盒中1元和2元面额钱币总额小于本次投入的钱币面额
            cout << "E003:Change is not enough, pay fail" << endl;
        } else if ((a[0] || a[1] || a[2] || a[3] || a[4] || a[5]) == 0) {
            // 商品全部为0
            cout << "E005:All the goods sold out" << endl;
        } else {
            //零钱盒中钱数增加
            if (num == 1 || num == 2)
                b[num - 1]++;
            else if (num == 5)
                b[2]++;
            else b[3]++;
            money += num; // 投入的总钱数增加
            cout << "S002:Pay success,balance=" << money << endl;
        }
    } else {
        // 不合法币种
        cout << "E002:Denomination error" << endl;
    }
}

// 购买函数
void buy(vector<int>& a, vector<int>& b, string& s) {
    // 检查命令是否是4位,第三位是否为A,第四位是否数字1-6
    if (s.length() == 4 && (s[2] == 'A') && (s[3] - '0' < 7) && isdigit(s[3]) &&
            (s[3] != '0')) {
        if (a[s[3] - '1'] == 0) {
            // 该商品的售罄
            cout << "E007:The goods sold out" << endl;
        } else if (price[s[3] - '1'] > money) {
            // 该商品价格大于投入的钱
            cout << "E008:Lack of balance" << endl;
        } else { // 成功购买
            money -= price[s[3] - '1']; // 投入的钱要减去买的商品
            a[s[3] - '1']--;
            cout << "S003:Buy success,balance=" << money << endl;
        }
    } else {
        // 输入命令不合法,商品不存在
        cout << "E006:Goods does not exist" << endl;
    }
}

// 退币函数
void back(vector<int>& coins) {
    int a = 0, b = 0, c = 0, d = 0; // 四个币种
    if (money == 0) {
        // 投入的没有钱了,不用退
        cout << "E009:Work failure" << endl;
    } else {
        d = money / 10; // 优先退大币额的数量
        if (d <= coins[3]) { // 10块的钱够退
            money = money % 10;
            coins[3] -= d;
        } else { // 10块的钱不够退
            d = coins[3]; // 全部退完
            coins[3] = 0;
            money -= d * 10; // 剩余要退的
        }
        c = money / 5; // 再计算要退的5块钱的数量
        if (c <= coins[2]) { // 5块的钱够退
            money = money % 5;
            coins[2] -= c;
        } else { // 5块的钱不够退
            c = coins[2]; // 全部退完
            coins[2] = 0;
            money -= d * 5; // 剩余要退的
        }
        b = money / 2; // 再计算要退的2块钱的数量
        if (b <= coins[1]) { // 2块的钱够退
            money = money % 2;
            coins[1] -= b;
        } else { // 2块的钱不够退
            b = coins[1]; // 全部退完
            coins[1] = 0;
            money -= d * 2; // 剩余要退的
        }
        a = money;  // 再计算要退的1块钱的数量
        if (a <= coins[0]) { // 1块的钱够退
            coins[0] -= a;
            money = 0;
        } else { // 1块的钱不够退
            coins[0] = 0;
            money -= a;
        }
        cout << "1 yuan coin number=" << a << endl;
        cout << "2 yuan coin number=" << b << endl;
        cout << "5 yuan coin number=" << c << endl;
        cout << "10 yuan coin number=" << d << endl;
    }
}

// 重载比较
bool cmp(pair<pair<string, int>, int>& a, pair<pair<string, int>, int>& b) {
    if (a.second != a.second) // 优先比较商品数量
        return a.second > b.second;
    else //再比较商品名字
        return a.first.first < b.first.first;
}

// 查询函数
void query(vector<int>& a, vector<int>& b, string& s) {
    if (s[1] == ' ' && s.length() == 3) { // 检查查询命令的合法性
        if (s[2] == 0) { // 类别为0
            vector<pair<pair<string, int>, int> > temp;
            for (int i = 0; i < 6; i++) {
                // 商品信息入vector方便排序输出
                temp.push_back(make_pair(make_pair("A" + char(i + 1), price[i]), a[i]));
            }
            sort(temp.begin(), temp.end(), cmp); // 按照重载后的比较排序
            // 输出
            for (int i = 0; i < 6; i++) 
                cout << temp[i].first.first << " " << temp[i].first.second << " " <<
                     temp[i].second << endl;
        } else if (s[2] == 1) { // 类别为1
            cout << "1 yuan coin number=" << b[0] << endl
                 << "2 yuan coin number=" << b[1] << endl
                 << "5 yuan coin number=" << b[2] << endl
                 << "10 yuan coin number=" << b[3] << endl;
        } else
            cout << "E010:Parameter error" << endl;
    } else
        cout << "E010:Parameter error" << endl;
}

int main()
{
    string s;
    vector<int> goods(6, 0);
    vector<int> coins(4, 0);
    while (getline(cin, s)) {
        vector<string> orders = split(s, ';');
        for (auto c : orders) {
            switch (c[0]) {
                case 'r': // 初始化
                    init(goods, coins, c);
                    break;
                case 'p': // 投币
                    pay(goods, coins, c);
                    break;
                case 'b': // 购买商品
                    buy(goods, coins, c);
                    break;
                case 'c': // 退币
                    back(coins);
                    break;
                case 'q': // 查询
                    query(goods, coins, c);
                    break;
            }
        }
    }
    return 0;
}
// 64 位输出请用 printf("%lld")

HJ99 自守数

描述
自守数是指一个数的平方的尾数等于该数自身的自然数。例如:25^2 = 625,76^2 = 5776,9376^2 = 87909376。请求出n(包括n)以内的自守数的个数。

输入描述:
int型整数

输出描述:
n以内自守数的数量。

代码:

#include <iostream>
using namespace std;

bool isSelfNum(int x) {
    string s1 = to_string(x), s2 = to_string(x * x);
    return s1 == s2.substr(s2.length() - s1.length());
}

int main() {
    int n;
    cin >> n;

    int count = 0;
    for (int i = 0; i <= n; i++)
        if (isSelfNum(i))
            count++;
    cout << count << endl;
    return 0;
}
// 64 位输出请用 printf("%lld")

HJ100 等差数列

描述
等差数列 2,5,8,11,14。。。。
(从 2 开始的 3 为公差的等差数列)
输出求等差数列前n项和。

输入描述:
输入一个正整数n。

输出描述:
输出一个相加后的整数。

代码:

#include <iostream>
using namespace std;

int main() {
    int n;
    cin >> n;

    int begin = 2, end = 2 + 3 * (n - 1);

    cout << (begin + end)*n / 2 << endl;
    return 0;
}
// 64 位输出请用 printf("%lld")

HJ101 输入整型数组和排序标识,对其元素按照升序或降序进行排序

描述
输入整型数组和排序标识,对其元素按照升序或降序进行排序。

输入描述:
第一行输入数组元素个数
第二行输入待排序的数组,每个数用空格隔开
第三行输入一个整数0或1。0代表升序排序,1代表降序排序

输出描述:
输出排好序的数字

代码:

#include <functional>
#include <iostream>
#include <vector>
using namespace std;

int main() {
    int n;
    cin >> n;
    vector<int> arr(n);
    for (int i = 0; i < n; i++)
        cin >> arr[i];
    int sorter;
    cin >> sorter;
    if (sorter)
        sort(arr.begin(), arr.end(), greater<>());
    else
        sort(arr.begin(), arr.end());

    for (int& x : arr)
        cout << x << " ";
    cout << endl;
    return 0;
}
// 64 位输出请用 printf("%lld")

HJ102 字符统计

描述
输入一个只包含小写英文字母和数字的字符串,按照不同字符统计个数由多到少输出统计结果,如果统计的个数相同,则按照ASCII码由小到大排序输出。

输入描述:
一个只包含小写英文字母和数字的字符串。

输出描述:
一个字符串,为不同字母出现次数的降序表示。若出现次数相同,则按ASCII码的升序输出。

代码:

#include <algorithm>
#include <iostream>
#include <unordered_map>
#include <vector>
using namespace std;

int main() {
    string s;
    cin >> s;
    unordered_map<char, int> mp;
    for (char& c : s)
        mp[c]++;
    vector<pair<char, int>> vp;
    for (auto &[c, cnt] : mp)
        vp.push_back(make_pair(c, cnt));
    sort(vp.begin(), vp.end(), [](const pair<char, int>& p1,
    const pair<char, int>& p2) {
        if (p1.second != p2.second)
            return p1.second > p2.second;
        else
            return p1.first < p2.first;
    });

    for (auto& p : vp)
        cout << p.first;
    cout << endl;
    return 0;
}
// 64 位输出请用 printf("%lld")

HJ103 Redraiment的走法

描述
Redraiment是走梅花桩的高手。Redraiment可以选择任意一个起点,从前到后,但只能从低处往高处的桩子走。他希望走的步数最多,你能替Redraiment研究他最多走的步数吗?

输入描述:
数据共2行,第1行先输入数组的个数,第2行再输入梅花桩的高度

输出描述:
输出一个结果

代码:

#include <iostream>
#include <vector>
using namespace std;

int main() {
    int n;
    cin >> n;
    vector<int> height(n);
    for (int i = 0; i < n; i++)
        cin >> height[i];
    // 状态数组
    vector<int> dp(n, 1);
    int ans = 0;
    // 状态转移
    for (int i = 1; i < n; i++)
        for (int j = 0; j < i; j++) {
            if (height[i] > height[j])
                dp[i] = max(dp[i], dp[j] + 1);
            ans = max(ans, dp[i]);
        }
    cout << ans << endl;
    return 0;
}
// 64 位输出请用 printf("%lld")

HJ105 记负均正II

描述
输入 n 个整型数,统计其中的负数个数并求所有非负数的平均值,结果保留一位小数,如果没有非负数,则平均值为0
本题有多组输入数据,输入到文件末尾。

输入描述:
输入任意个整数,每行输入一个。

输出描述:
输出负数个数以及所有非负数的平均值

代码:

#include <cstdio>
#include <iostream>
using namespace std;

int main() {
    int x;
    int cnt1 = 0, cnt2 = 0;
    double sum = 0.0;
    while (cin >> x) {
        if (x < 0)
            cnt1++;
        else {
            cnt2++;
            sum += x;
        }
    }
    cout << cnt1 << endl;
    printf("%.1lf\n", sum / cnt2);
    return 0;
}
// 64 位输出请用 printf("%lld")

HJ106 字符逆序

描述
将一个字符串str的内容颠倒过来,并输出。

输入描述:
输入一个字符串,可以有空格

输出描述:
输出逆序的字符串

代码:

#include <iostream>
using namespace std;

int main() {
    string s;
    getline(cin, s);
    for (int i = s.length() - 1; i >= 0; i--)
        cout << s[i];
    return 0;
}
// 64 位输出请用 printf("%lld")

HJ107 求解立方根

描述
计算一个浮点数的立方根,不使用库函数。
保留一位小数。

输入描述:
待求解参数,为double类型(一个实数)

输出描述:
输出参数的立方根。保留一位小数。

代码:

#include <cmath>
#include <cstdio>
#include <iostream>
using namespace std;

int main() {
    double num;
    cin >> num;

    // 二分查找
    double left = num > -1 ? -1 : num, right = num > 1 ? num : 1;
    double mid;
    while (fabs(right - left) > 1e-8) {
        mid = (left + right) / 2;
        if (num - pow(mid, 3) <= 1e-8)
            right = mid;
        else
            left = mid;
    }
    printf("%.1lf\n", mid);
    return 0;
}
// 64 位输出请用 printf("%lld")

HJ108 求最小公倍数

描述
正整数A和正整数B 的最小公倍数是指 能被A和B整除的最小的正整数值,设计一个算法,求输入A和B的最小公倍数。

输入描述:
输入两个正整数A和B。

输出描述:
输出A和B的最小公倍数。

代码:

#include <iostream>
using namespace std;

int gcd(int a, int b) {
    if (b == 0)
        return a;
    return gcd(b, a % b);
}

int main() {
    int a, b;
    cin >> a >> b;
    cout << a* b / gcd(a, b) << endl;
    return 0;
}
// 64 位输出请用 printf("%lld")
  • 17
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
108中有部分目重合,因此么有收录在压缩文件中。 华为机试 ├─001 字符串最后一个单词长度 │ └─Source ├─002 计算字符个数 │ └─Source ├─003 明明的随机数 │ └─Source ├─004 字符串分隔 │ └─Source ├─005 进制转换 │ └─Source ├─006 质数因子 │ └─Source ├─007 取近似值 │ └─Source ├─008 合并表记录 │ └─Source ├─009 提取不重复的整数 │ └─Source ├─010 字符个数统计 │ └─Source ├─011 数字颠倒 │ └─Source ├─012 字符串反转 │ └─Source ├─013 句子逆序 │ └─Source ├─014 字典序排序 │ └─Source ├─015 求int型正整数在内存中存储是1的个数 │ └─Source ├─016 购物单 │ ├─Debug │ ├─Source │ │ └─Debug │ ├─Source - 时间优先 │ │ └─Debug │ └─Source - 空间优先 │ ├─Debug │ └─Release ├─017 坐标移动 ├─018 识别IP地址分类统计 │ └─Source │ └─Debug ├─019 错误记录 ├─020 密码验证合格程序 ├─021 密码破解 ├─023 删除字符串中出现次数最少字符 │ └─Source │ └─Debug ├─024 合唱队 │ └─Source │ ├─Debug │ └─Release ├─025 数据分类处理 │ └─Source │ └─Debug ├─026 查找兄弟单词 │ └─Source │ └─Debug ├─027 素数伴侣 │ └─Source │ └─Debug ├─028 字符串合并处理 │ └─Source │ └─Debug ├─030 密码截取(查找最长回文字符串) ├─031 蛇形矩阵 │ └─Source │ └─Debug ├─033 判断IP是否属于同一子网 │ └─Source │ └─Debug ├─034 称砝码 │ └─Source │ └─Debug ├─035 学英语 │ └─Source │ └─Debug ├─036 迷宫问 │ └─Source │ └─Debug ├─037 数独问 │ └─Debug ├─038 名字漂亮度 │ └─Source │ └─Debug ├─039 字符串截取 │ └─Source │ └─Debug ├─040 单链表删除数据 │ └─Source │ └─Debug ├─041 多线程 │ └─Source │ ├─Backup │ ├─Debug │ │ └─041.tlog │ └─Release │ └─041.tlog ├─042 表达式计算 │ └─Source │ └─Debug ├─043 计算字符串距离 │ └─Source │ └─Debug ├─044 杨辉三角形变形 ├─046 挑7 ├─047 完全数 │ └─Debug ├─048 高精度加法 ├─049 输出n个数中最小的k个 │ └─Debug ├─050 找出字符串只出现一次的字符 │ └─Debug ├─051 组成一个偶数最接近的2个质数 │ └─Debug ├─052 M个苹果放入N个盘子 ├─053 查找整数二进制中1的个数 ├─054 DNA子串 ├─055 MP3光标位置 │ └─Source │ └─Debug ├─056 查找2个字符串最大相同子串 │ └─Debug ├─057 配置文件恢复 │ └─Source │ └─Debug ├─058 24点计算 │ └─Debug ├─059 成绩排序 ├─060 矩阵相乘 ├─061 矩阵乘法次数计算 ├─062 字符串通配符 │ └─Debug ├─066 命令行解析 │ └─Source │ └─Debug ├─067 最大相同子串长度 │ └─Debug ├─068 火车编号进站 │ └─Debug ├─072 数组合并 ├─074 埃及分数 │ └─Source │ └─Debug ├─076 密码截取 │ └─Source ├─077 求最大连续bit数 ├─078 密码强度 ├─079 扑克牌大小 │ └─Source │ └─Debug ├─081 合法IP ├─082 棋盘格子走法 ├─083 在字符串中找出连续最长数字串 ├─084 int数组分组,两组和相等 │ └─Source │ └─Debug ├─086 人民币转换 │ └─Source │ └─Debug ├─087 表示数字 ├─090 自动售货系统 │ └─Source │ └─Debug └─091 24点输出 └─Debug
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

UestcXiye

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

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

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

打赏作者

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

抵扣说明:

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

余额充值