PAT甲级题目答案汇总PAT (Advanced Level) Practice (更新中)AcWing

第一章、字符串处理

1001 A+B Format (20 分)

  • 题意 :将整数转换成标准格式
  • 思路 :从后往前遍历字符串进行模拟,每三个数字加一个逗号,但不能是在最前面加逗号,也不能是加在负号后面
  • 语法 :使用string和to_string函数不需要头文件
#include <iostream>

using namespace std;

int main()
{
    int a, b;
    cin >> a >> b;
    string num = to_string(a + b);
    string ans = "";
    for (int i = num.size() - 1, j = 0; i >= 0; i -- )
    {
        ans = num[i] + ans;
        ++ j;
        if (j % 3 == 0 && i && num[i - 1] != '-') ans = "," + ans;
    }
    
    cout << ans;
    
    return 0;
}


1005 Spell It Right (20 分)

  • 题意 :得到输入数的各位之和后按位输出分别的英文
  • 语法 :行末无空格,可以先输出第一位后,分别输出一个空格加每一位
#include <iostream>

using namespace std;

string word[] = {"zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine"};

int main()
{
    string n;
    cin >> n;
    
    int s = 0;
    for (auto c : n) s += c - '0';
    
    string str = to_string(s);
    
    cout << word[str[0] - '0'];
    for (int i = 1; i < str.size(); i ++ ) cout << ' ' << word[str[i] - '0'];
    
    return 0;
}


1006 Sign In and Sign Out (25 分)

  • 题意 :在输入的每个第二个字符串中找最小的,第三个找最大的,输出它们分别对应的第一个字符串
#include <iostream>

using namespace std;

int main()
{
    string open_id, open_time;
    string close_id, close_time;
    
    int m;
    cin >> m;
    
    for (int i = 0; i < m; i ++ )
    {
        string id, in_time, out_time;
        cin >> id >> in_time >> out_time;
        
        //  更新
        if (!i || in_time < open_time)
        {
            open_id = id;
            open_time = in_time;
        }
        
        if (!i || out_time > close_time)
        {
            close_id = id;
            close_time = out_time;
        }
    }
    
    cout << open_id << ' ' << close_id;
    
    return 0;
}

1035 Password (20 分)

  • 题意 :输入的每行的第二个字符串中按照题意替换字符,并且记录被替换过的这两个字符串,按要求输出
  • 思路 :数组记录即可,因为是按顺序一一对应的
  • 语法 :puts和printf在这种时候比较方便。
#include <iostream>

using namespace std;

const int N = 1010;

string name[N], pwd[N];

string change(string str)
{
    string res;

    for (auto c : str)
        if (c == '1') res += '@';
        else if (c == '0') res += '%';
        else if (c == 'l') res += 'L';
        else if (c == 'O') res += 'o';
        else res += c;

    return res;
}

int main()
{
    int n;
    cin >> n;
    
    int m = 0;
    for (int i = 0; i < n; i ++ )
    {
        string a, b;
        cin >> a >> b;
        
        string c = change(b);
        
        if (b != c) name[m] = a, pwd[m ++ ] = c;
    }
    
    if (!m)
    {
        if (n == 1) puts("There is 1 account and no account is modified");
        else printf("There are %d accounts and no account is modified", n);
    }
    else
    {
        cout << m << endl;
        for (int i = 0; i < m; i ++ ) cout << name[i] << ' ' << pwd[i] << endl;
    }
    
    return 0;
}

1050 String Subtraction (20 分)

  • 题意 :给两个字符串,在第一个字符串中将在第二个中出现过的字符全部删除
  • 语法 : g e t l i n e getline getline函数在 i o s t r e a m iostream iostream头文件中;unordered_set的count函数和insert函数
#include <iostream>
#include <unordered_set>

using namespace std;

int main()
{
    string s1, s2;
    getline(cin, s1);
    getline(cin, s2);
    
    unordered_set<char> hash;
    for (auto c : s2)   hash.insert(c);
    
    string res;
    for (auto c : s1)
        if (!hash.count(c))
            res += c;
    
    cout << res;
    
    return 0;
}

1061 Dating (20 分)

  • 题意 :captive letter大写字母;case sensitive区分大小写;common共同的
  • 题意 :先找到第一二个字符串中第一个一样的且符合条件的大写字母,然后是第二个一样的且符合条件大写字母,然后找第三四个字符串中第一个符合条件且一样的字母
  • 思路 :要看清题目背后含义,字母范围;在第一个和第二个的输出中,如果写在同一个循环里,第一个满足后用了bool还不够,还要加一个continue,否则直接进入了第二个判断条件,而采用标准写法用两个while就没有这个问题;
  • 语法 :时间题常见用printf的%02d;printf选择句式;ASCII码中从小到大分别是,数字,大写字母,小写字母;或中的与不需要括号;a[k] - ‘A’ + 10
#include <iostream>

using namespace std;

int main()
{
    string a, b, c, d;
    cin >> a >> b >> c >> d;
    
    int k = 0;
    while (true)
    {
        if (a[k] == b[k] && 'A' <= a[k] && 'G' >= a[k]) break;
        k ++ ;
    }
    
    char weekdays[7][4] = {"MON", "TUE", "WED", "THU", "FRI", "SAT", "SUN"};

    printf("%s ", weekdays[a[k] - 'A']);
    
    k ++ ;
    
    while (true)
    {
        if (a[k] == b[k] && (a[k] >= '0' && a[k] <= '9' || a[k] >= 'A' && a[k] <= 'N')) break;
        k ++ ;
    }
    
    printf("%02d:", a[k] <= '9' ? a[k] - '0' : a[k] - 'A' + 10);
    
    for (int i = 0;; i ++ )
        if (c[i] == d[i] && (c[i] >= 'a' && c[i] <= 'z' || c[i] >= 'A' && c[i] <= 'Z'))
        {
            printf("%02d", i);
            break;
        }
    
    return 0;
}

1073 Scientific Notation (20 分)

  • 题意 :科学计数法转数字
  • 思路 :当科学计数法系数>0时,有可能不仅无法加零,还去不了小数点;注意题目有个关键地方,无论这个数是正负,第一位是符号位
  • 语法 :string的find函数;substr若只有一个参数,那个参数是pos,返回包含pos在内后面的整个字符串;string函数,先长度后内容
#include <iostream>

using namespace std;

int main()
{
    string s;
    cin >> s;
    
    if (s[0] == '-') cout << '-';
    int k = s.find('E');
    
    string a = s[1] + s.substr(3, k - 3);
    int b = stoi(s.substr(k + 1));
    
    if (b <= 0) cout << "0." << string(- b - 1, '0');
    else if (b < a.size() - 1) a = a.substr(0, b + 1) + '.' + a.substr(b + 1);
    else a += string(b - a.size() + 1, '0');
    
    cout << a;
    
    return 0;
}

1077 Kuchiguse (20 分)

  • 题意 :给n个字符串,找这n个字符串最长的公共后缀( 2 < = N < = 100 2<=N<=100 2<=N<=100 m a x l e n < = 256 maxlen <= 256 maxlen<=256
  • 语法 :与getline搭配使用getchar!reverse在algorithm中;substr只传一个参数的妙用,后缀
#include <iostream>

using namespace std;

const int N = 110;

string s[N];

int main()
{
    int n;
    cin >> n;
    getchar();
    
    for (int i = 0; i < n; i ++ ) getline(cin, s[i]);
    
    for (int k = s[0].size(); k; k -- )
    {
        string sf = s[0].substr(s[0].size() - k);
        bool is_matched = true;
        
        for (int i = 1; i < n; i ++ )
            if (s[i].size() < k || s[i].substr(s[i].size() - k) != sf)
            {
                is_matched = false;
                break;
            }
        
        if (is_matched)
        {
            cout << sf;
            return 0;
        }
    }
    
    cout << "nai";
    
    return 0;
}

1084 Broken Keyboard (20 分)

  • 题意 :The English letters must be capitalized英文字母必须大写
  • 题意 :给两个字符串,找第二个字符串中在第一个中没有出现的字符,无视大小写
  • 思路 :双指针即可,b中有的a中一定有,反之不一定,且按顺序,利用好这种性质,a为主指针,将b中与a一一比对;为了防止数组越界,要在b中最后加上一个a中没有出现过的字符
  • 语法 :char = toupper(char);ASCII码才127之间,且可以直接以char当数组下标;让一个数组全部都是某个具体数值的方法
#include <iostream>

using namespace std;

int main()
{
    string a, b;
    cin >> a >> b;
    
    bool st[200] = {0};
    
    b += '#';
    
    for (int i = 0, j = 0; i < a.size(); i ++ )
    {
        char x = toupper(a[i]), y = toupper(b[j]);
        if (x == y) j ++ ;
        else
        {
            if (!st[x]) st[x] = true, cout << x;
        }
    }
    
    return 0;
}

1108 Finding Average (20 分)

  • 题意 :number和numbers
  • 题意 :输入n个字符串,判断分别是否是合法数字(大小,小数点后位数,无效字符)
  • 思路 :看小数点后是否合法时,如果点在最后一位,num.size() - k就会是1,在倒数第二位,就会是2,倒数第三位等于3,在倒数第三位时后面有两位有效数字,所以大于三,就多于两位有效数字
  • 语法 :stof(float实数)可以帮我们判断输入字符串是否合法,如果不合法会抛出异常,所以只要写try,catch语句,如果是合法数字,再判断是否在正负一千以内,小数点后是否最多两位;但这个函数有一个问题5.2abc也被算作合法数字,它会看这个字符串的前几位能否构成合法实数, 如果能,它就只用前几位,所以这里还要判断最终位数。size_t是记录用了几个字符,如果用的字符的数量小于num.size,说明就是5.2abc形式,也不是合法的;**catch(…)**表示接收任何类型的异常;string.findk!=-1就是存在小数点;string.c_str();且以上这些不需要其它额外的头文件
#include <iostream>

using namespace std;

int main()
{
    int n;
    cin >> n;
    
    double sum = 0;
    int cnt = 0;
    
    while (n -- )
    {
        string num;
        cin >> num;
        double x;
        
        bool success = true;
        try
        {
            size_t idx;
            x = stof(num, &idx);
            if (idx < num.size()) success = false;
        }
        catch(...)
        {
            success = false;
        }
        
        if (x < -1000 || x > 1000) success = false;
        int k = num.find('.');
        if (k != -1 && num.size() - k > 3) success = false;
        
        if (success) cnt ++ , sum += x;
        else printf("ERROR: %s is not a legal number\n", num.c_str());
    }
    
    if (cnt > 1) printf("The average of %d numbers is %.2lf", cnt, sum / cnt);
    else if (cnt == 1) printf("The average of 1 number is %.2lf", sum);
    else printf("The average of 0 numbers is Undefined");
    
    return 0;
}

1124 Raffle for Weibo Followers (20 分)

  • 题意 :给n个字符串,输出从开始位置每隔m个位置的字符串,要跳过已经被输出过的
  • 思路 :模拟就是从第一个开始的位置输出,然后每次跳到n个位置后,如果跳到的位置已经被输出过,那就跳过;索性用数组记录位置对应的字符串,就不用for了;用set判断是否已经被输出过以及有没有输出过字符串。
#include <iostream>
#include <unordered_set>

using namespace std;

const int N = 1e3 + 10;

string name[N];

int main()
{
    int m, n, s;
    cin >> m >> n >> s;
    
    unordered_set<string> se;
    
    for (int i = 1; i <= m; i ++ ) cin >> name[i];
    
    int k = s;
    while (k <= m)
    {
        if (se.find(name[k]) != se.end()) k ++ ;
        else
        {
            cout << name[k] << endl;
            se.insert(name[k]);
            k += n;
        }
    }
    
    if (se.empty()) cout << "Keep going...";
    
    return 0;
}

第二章、高精度

1002 A+B for Polynomials (25 分)

  • 题意 :给两个多项式,输出两个多项式相加结果的系数和次数
  • 思路 :用double数组记录多项式,正好数组下标是整数,系数是double
#include <iostream>

using namespace std;

const int N = 1010;

double a[N], b[N], c[N];

int main()
{
    int k;
    
    cin >> k;
    while (k -- )
    {
        int ex;
        double co;
        cin >> ex >> co;
        a[ex] = co;
    }
    
    cin >> k;
    while (k -- )
    {
        int ex;
        double co;
        cin >> ex >> co;
        b[ex] = co;
    }
    
    for (int i = 0; i < N; i ++ ) c[i] = a[i] + b[i];
    
    k = 0;
    for (int i = 0; i < N; i ++ )
        if (c[i])
            k ++ ;
    
    cout << k;
    
    for (int i = N - 1; i >= 0; i -- )
        if (c[i])
            printf(" %d %.1lf", i, c[i]);
    
    return 0;
}

1009 Product of Polynomials (25 分)

  • 题意 :给两个多项式,输出两个多项式相乘结果的系数和次数
  • 语法 :使用函数化解这个不同的容器相同操作的尴尬;正确认知数组实际应有的容量,尽量开大
#include <iostream>

using namespace std;

const int N = 1010, M = N * 2;

double a[N], b[N], c[M];

void input(double a[])
{
    int k;
    cin >> k;
    while (k -- )
    {
        int n;
        double v;
        cin >> n >> v;
        a[n] = v;
    }
}

int main()
{
    input(a);
    input(b);
    
    for (int i = 0; i < N; i ++ )
        for (int j = 0; j < N; j ++ )
            c[i + j] += a[i] * b[j];
    
    int k = 0;
    for (int i = 0; i < M; i ++ )
        if (c[i])
            k ++ ;
    
    cout << k;
    for (int i = M - 1; i >= 0; i -- )
        if (c[i])
            printf(" %d %.1lf", i, c[i]);
    
    return 0;
}

1023 Have Fun with Numbers (20 分)

在这里插入图片描述

  • 题意 :将n乘以二后得到的数的每一位数字是否和n中个数一样
  • 思路 :高精度加法(整数) 就是在int和long long都存不下来时用;个位存在a[0]的位置(倒着放);如何判断两个vector数组中无关顺序的情况下所存数一样呢 ?排序后直接比较。
  • 语法 :vector之间 支持比较运算,可以按照字典序判断两个序列大小关系;sort函数在algorithm头文件中。
#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

int main()
{
    string A;
    vector<int> a;

    cin >> A;
    for (int i = A.size() - 1; i >= 0; i -- ) a.push_back(A[i] - '0');
    
    vector<int> b;
    
    int t = 0;
    for (int i = 0; i < a.size(); i ++ )
    {
        int s = a[i] + a[i] + t;
        b.push_back(s % 10);
        t = s / 10;
    }
    if (t) b.push_back(1);
    
    vector<int> c = b;
    
    sort(c.begin(), c.end());
    sort(a.begin(), a.end());
    
    if (a == c) puts("Yes");
    else puts("No");
    
    for (int i = b.size() - 1; i >= 0; i -- ) cout << b[i];
    
    return 0;
}

1058 A+B in Hogwarts (20 分)

在这里插入图片描述

  • 思路 :实则就是进位制的操作,不用if特判

  • 语法 :scanf和printf的妙用

#include <iostream>

using namespace std;

int main()
{
    int a, b, c, d, e, f;
    scanf("%d.%d.%d %d.%d.%d", &a, &b, &c, &d, &e, &f);
    a += d, b += e, c += f;
    
    b += c / 29, c %= 29;
    a += b / 17, b %= 17;
    printf("%d.%d.%d", a, b, c);
    
    return 0;
}

1136 A Delayed Palindrome (20 分)

  • 题意 :输入一数,循环将其与逆序相加得到一新数,直到新数为回文串
  • 思路 :注意每次循环里面是先check再进行后续操作(包括等式)的,否则会wa,想象比如输入的就是回文数的情况;且第十次出去的如果是的话,也是回文数要输出;一般先放最低位到vector中;高精度加法的写法;函数化程序
  • 语法 :将一个vector逆序复制给另一个vector;从string转换到vector的时候记得-‘0’
#include <iostream>
#include <vector>

using namespace std;

bool check(vector<int> A)
{
    for (int i = 0, j = A.size() - 1; i < j; i ++ , j -- )
        if (A[i] != A[j])
            return false;
    return true;
}

void print(vector<int> A)
{
    for (int i = A.size() - 1; i >= 0; i -- )
        cout << A[i];
}

vector<int> add(vector<int> A, vector<int> B)
{
    vector<int> C;
    for (int i = 0, t = 0; i < A.size() || i < B.size() || t; i ++ )
    {
        if (i < A.size()) t += A[i];
        if (i < B.size()) t += B[i];
        C.push_back(t % 10);
        t /= 10;
    }
    
    return C;
}

int main()
{
    string a;
    cin >> a;
    
    vector<int> A;
    for (int i = 0; i < a.size(); i ++ ) A.push_back(a[a.size() - 1 - i] - '0');
    
    for (int i = 0; i < 10; i ++ )
    {
        if (check(A)) break;
        
        vector<int> B(A.rbegin(), A.rend());
        
        print(A), cout << " + ", print(B), cout << " = ";
        A = add(A, B);
        print(A), cout << endl;
    }
    
    if (check(A)) print(A), cout << " is a palindromic number.";
    else cout << "Not found in 10 iterations.";
    
    return 0;
}

第三章、进位制

1010 Radix (25 分)

  • 题意 :radix进制
  • 题意 :给两个数和其中一个数的进制,问另一个数能否在某一进制下与这数相等
  • 思路 :如果tag等于2就交换,最后还是只需要处理tag为1这种情况,这种思路值得学习;第一步,将n1转换成十进制,考虑这是否能存下,n1不超过十位数字,所以最大是十个z,也就是三十六进制,十个z小于1后面十个0,也就是小于 3 6 10 36^{10} 3610,3e15多些,也就是说可以用long long存下;第二步,判断n2在什么进制下等于target,注意n2可能不止36进制,比如n2是 ( 10 ) b = b (10)_b=b (10)b=b,n1最大又是3e15,所以我们最大可以弄一个3e15次方,所以枚举的时候不止枚举到36次 ,也就是说这个枚举的区间非常大,我们就想到能否能用二分来求呢,我们发现,当枚举的进制变大时,n2也会变大,这是一个单调的过程,所以我们可以用二分来求这个进制;
  • 二分需要一个左右边界,右边界是target+1,左边界应该等于n2的最大的这一位加1
  • 在calc中,res可能会爆long long,如果太大,大于1e16了已经,我们知道n1最大值是3e15,此时一定无解,则直接返回1e18;注意calc中参数的进制r也是要用long long的
  • r如果直接取target,那么6 6 1 10这个样例会返回6,但答案是7。
  • 注意代码中多次将int主动转成long long的情形
  • 两个数相乘的结果可能long long也存不下,溢出可能变成负数也可能变成正数,所以要用double
  • 语法 :swap函数在algoeithm 头文件中
#include <iostream>
#include <algorithm>

using namespace std;

typedef long long ll;

int get(char c)
{
    if (c <= '9') return c - '0';
    return c - 'a' + 10;
}

ll calc(string n, ll r)
{
    ll res = 0;
    for (auto c : n)
    {
        if ((double)res * r + get(c) > 1e16) return 1e18;
        res = res * r + get(c);
    }
    return res;
}

int main()
{
    string n1, n2;
    cin >> n1 >> n2;
    int tag, radix;
    cin >> tag >> radix;
    
    if (tag == 2) swap(n1, n2);
    ll target = calc(n1, radix);
    
    ll l = 0, r = target + 1;
    // ll l = 0, r = max(target, 36ll);
    for (auto c : n2) l = max(l, (ll)get(c) + 1);
    
    while (l < r)
    {
        ll mid = l + r >> 1;
        if (calc(n2, mid) >= target) r = mid;       // == problem!
        else l = mid + 1;
    }
    
    if (calc(n2, r) == target) cout << r;
    else cout << "Impossible";
    
    return 0;
}

1015 Reversible Primes (20 分)

  • 题意 :首先判断N是不是质数。然后将N转成D进制数,将D进制数翻转后,转回十进制数,看得到的这个数是否是质数。
  • 思路 : n n n% d d d是n在d进制下最后一位数,也就是在d进制下的个位,在翻转后,这位应该是第一位,将翻转后的结果变成十进制时是要从最高位开始做。这样就将最后三步化为了一步。
  • 语法 :逗号表达式的值是最后一个的值; N N N最大是 1 0 5 10^5 105,那么如果是二进制的话就会有十几位,十五六位,所以得用 l o n g l o n g long long longlong存转换之后的结果。
#include <iostream>

using namespace std;

typedef long long LL;

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

bool check(int n, int d)
{
    if (!is_prime(n)) return false;
    
    LL r = 0;
    while (n)
    {
        r = r * d + n % d;
        n /= d;
    }
    
    return is_prime(r);
}

int main()
{
    int n, d;
    while (cin >> n >> d, n >= 1)
    {
        if (check(n, d)) puts("Yes");
        else puts("No");
    }
    
    return 0;
}

1019 General Palindromic Number (20 分)

  • 题意 :给出一个数和一个进制,判断这个数在这个进制下的结果是否是回文数。
  • 思路 :判断回文数(i只要<j就可以了);十进制转其它进制,用vector存更方便;十进制转其它进制,注意n为0的情况要特殊讨论;十进制转其它进制时,先得到的是其它进制下的最低位,因为它最先被放入vector,且在输出其它进制下的这个数时,是从高位向低位输出,所以先从vector的最后一位开始输出。
  • 语法 :reverse函数在algorithm头文件;使用vector记得加头文件vector;vector最后一个元素,back()
#include <iostream>
#include <vector>

using namespace std;

vector<int> nums;

bool check()
{
    for (int i = 0, j = nums.size() - 1; i < j; i ++ , j -- )
        if (nums[i] != nums[j])
            return false;
    
    return true;
}

int main()
{
    int n, b;
    cin >> n >> b;
    
    if (!n) nums.push_back(0);
    while (n) nums.push_back(n % b), n /= b;
    
    if (check()) puts("Yes");
    else puts("No");
    
    cout << nums.back();
    for (int i = nums.size() - 2; i >= 0; i -- ) cout << ' ' << nums[i];
    
    return 0;
}

1027 Colors in Mars (20 分)

  • 题意 :将输入的十进制数转为十三进制数
  • 思路 :注意这里输入的十进制数最大为168,意味着转化为十三进制后最多只有两个数字,这也恰好可以解决题目要求的如果只有一位数字必须左添0,也就是说无论如何输出的都是两位数字的十三进制数;注意这种将十进制数转为大于十的进制数的“get“方式。
  • 语法 :int转char
#include <iostream>

using namespace std;

int a[3];

char get(int x)
{
    if (x > 9) return 'A' + x - 10;
    return '0' + x;
}

int main()
{
    for (int i = 0; i < 3; i ++ ) cin >> a[i];
    
    cout << '#';
    
    for (int i = 0; i < 3; i ++ ) cout << get(a[i] / 13) << get(a[i] % 13);
    
    return 0;
}

1100 Mars Numbers (20 分)

在这里插入图片描述

  • 思路 :重要的一点是高进制和低进制的英文单词没有重复,所以可以直接连接在同一个数组中
  • 语法 :stringstream头文件为sstream
#include <iostream>
#include <sstream>

using namespace std;

char names[][5] = {"tret", "jan", "feb", "mar", "apr", "may", "jun", "jly", "aug", "sep", "oct", "nov", "dec", "tam", "hel", "maa", "huh", "tou", "kes", "hei", "elo", "syy", "lok", "mer", "jou"};

int get(string word)
{
    for (int i = 0; i < 25; i ++ )
        if (names[i] == word)
        {
            if (i < 13) return i;
            return 13 * (i - 12);
        }
    return -1;      // 一定不会执行
}

int main()
{
    int T;
    cin >> T;
    getchar();
    
    while (T -- )
    {
        string line;
        getline(cin, line);
        
        stringstream ssin(line);
        
        if (line[0] <= '9')
        {
            int v;
            ssin >> v;
            if (v < 13) cout << names[v] << endl;
            else
            {
                cout << names[12 + v / 13];
                if (v % 13 != 0) cout << " " << names[v % 13];
                cout << endl;
            }
        }
        else
        {
            string word;
            int res = 0;
            
            while (ssin >> word) res += get(word);
            cout << res << endl;
        }
    }
}

第四章、排序

1012 The Best Rank (25 分)

  • 题意 :给ID和3门成绩,计算其平均分A,输出每位学生最好的排名,A>C>M>E
  • 思路 :如果将所需的若干个元素中使第一个元素为后几个的平均值;容器内二分找值;题目所给ACME决定了搜索顺序,因此决定了容器顺序;二分时,如果是倒序的,就应该找最前面的,这里我们为了省事不写cmp说明是从小到大的,那么我们要找的就是最后一个,最后一个等于x的数的位置,然后如果说r是a.size() - 1,说明排名是第一,那么返回1,也就是说返回值是a.size() - r
  • 语法 :round函数四舍五入,头文件是cmath;map的count用来找是否存在这个左值;int t[4]= {0];数组内统一初始值
#include <iostream>
#include <vector>
#include <unordered_map>
#include <algorithm>
#include <cmath>

using namespace std;

unordered_map<string, vector<int>> grades;
vector<int> q[4];       // A C M E

int get_grade(vector<int> &a, int x)
{
    int l = 0, r = a.size() - 1;
    while (l < r)
    {
        int mid = (l + r + 1) >> 1;
        if (a[mid] <= x) l = mid;
        else r = mid - 1;
    }
    return a.size() - r;
}

int main()
{
    int n, m;
    cin >> n >> m;
    
    for (int i = 0; i < n; i ++ )
    {
        string id;
        cin >> id;
        
        int t[4] = {0};
        for (int j = 1; j < 4; j ++ )
        {
            cin >> t[j];
            t[0] += t[j];
        }
        
        t[0] = round(t[0] / 3.0);
        for (int j = 0; j < 4; j ++ )
        {
            grades[id].push_back(t[j]);
            q[j].push_back(t[j]);
        }
    }
    
    for (int i = 0; i < 4; i ++ ) sort(q[i].begin(), q[i].end());
    
    char names[] = "ACME";
    
    while (m -- )
    {
        string id;
        cin >> id;
        if (grades.count(id) == 0) puts("N/A");
        else
        {
            int res = n + 1;
            char c;
            for (int i = 0; i < 4; i ++ )
            {
                int rank = get_grade(q[i], grades[id][i]);
                // int rank = 1 + n - (upper_bound(q[i].begin(), q[i].end(), grades[id][i]) - q[i].begin());		// 在vector要逆序的情况下
                if (res > rank)
                {
                    res = rank;
                    c = names[i];
                }
            }
            cout << res << ' ' << c << endl;
        }
    }
}

第五章、树

第六章、图论

1003 Emergency (25 分)

  • 题意 :求无向图中最短路的数量,以及在最短路情况下,点权之和最大是多少
  • 思路 :dijkstra的扩展一般在第三步“用t更新其它点“;spfa不能用来求最短路的数量(因为每个点可能被更新多次);假设有三个点可以走到终点x,那么从起点s走到x的路径分为三类,s->1->x…,如果d1<d2<d3,最短距离的数量就是走到第一个点的数量,如果d1=d2<d3,前两个相加,同理,求最短路情况下点权和最大,就是三者取max(如果三者相同);cnt数组记录从起点走到i的最短路径数量;sum数组记录从起点到i的最大点权
  • 语法 :如果点数<=1000,邻接矩阵就没有问题,>=1e4就一定要邻接表存;
#include <iostream>
#include <cstring>

using namespace std;

const int N = 510;

int n, m, S, T;
int w[N], g[N][N];
int cnt[N], sum[N];
int dist[N];
bool st[N];

void dijkstra()
{
    memset(dist, 0x3f, sizeof dist);		// 初始化
    
    dist[S] = 0, cnt[S] = 1, sum[S] = w[S];
    
    for (int i = 0; i < n - 1; i ++ )
    {
        int t = -1;
        for (int j = 0; j < n; j ++ )
            if (!st[j] && (t == -1 || dist[t] > dist[j]))
                t = j;
        
        st[t] = true;		// 标记
        
        for (int j = 0; j < n; j ++ )
            if (dist[j] > dist[t] + g[t][j])
            {
                dist[j] = dist[t] + g[t][j];
                cnt[j] = cnt[t];
                sum[j] = sum[t] + w[j];
            }
            else if (dist[j] == dist[t] + g[t][j])
            {
                cnt[j] += cnt[t];
                sum[j] = max(sum[j], sum[t] + w[j]);
            }
    }
}

int main()
{
    cin >> n >> m >> S >> T;
    
    for (int i = 0; i < n; i ++ ) cin >> w[i];
    
    memset(g, 0x3f, sizeof g);		// 初始化
    
    while (m -- )
    {
        int a, b, c;
        cin >> a >> b >> c;
        g[a][b] = g[b][a] = min(g[a][b], c);		// 无向图
    }
    
    dijkstra();
    
    cout << cnt[T] << ' ' << sum[T];
    
    return 0;
}

在这里插入图片描述

  • 思路 :dijkstra中在循环for或者while的外面初始化时,起点的st不要设成true!堆优化版在一个点被更新松弛后将它放入优先队列内
  • 语法 :堆优化版写成链式前向星,M开成N*N
// 堆优化版
#include <iostream>
#include <cstring>
#include <queue>

using namespace std;

const int N = 510, M = N * N;       // 注意M大小

typedef pair<int, int> pii;

int h[N], w[M], e[M], ne[M], idx;
int wt[N];
int dist[N];
bool st[N];
int cnt[N], sum[N];
int n, m, S, T;

void add(int a, int b, int c)
{
    e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx ++ ;
}

void dijkstra()
{
    memset(dist, 0x3f, sizeof dist);
    dist[S] = 0;
    cnt[S] = 1, sum[S] = wt[S];
    
    priority_queue<pii, vector<pii>, greater<pii>> heap;
    heap.push({0, S});
    
//    st[S] = true;         注意!!!
    
    while (heap.size())
    {
        auto t = heap.top();
        heap.pop();
        
        int ver = t.second, distance = t.first;
        
        if (st[ver]) continue;
        st[ver] = true;
        
        for (int i = h[ver]; i != -1; i = ne[i])
        {
            int j = e[i];
            if (dist[j] > dist[ver] + w[i])
            {
                dist[j] = dist[ver] + w[i];
                cnt[j] = cnt[ver];
                sum[j] = sum[ver] + wt[j];
                heap.push({dist[j], j});        // 被更新松弛了的点要放入优先队列内
            }
            else if (dist[j] == dist[ver] + w[i])
            {
                cnt[j] += cnt[ver];
                sum[j] = max(sum[j], sum[ver] + wt[j]);
            }
        }
    }
}

int main()
{
    memset(h, -1, sizeof h);
    
    cin >> n >> m >> S >> T;
    
    for (int i = 0; i < n; i ++ ) cin >> wt[i];
    
    while (m -- )
    {
        int a, b, c;
        cin >> a >> b >> c;
        add(a, b, c);
        add(b, a, c);
    }
    
    dijkstra();
    
    cout << cnt[T] << ' ' << sum[T];
    
    return 0;
}

第七章、数学

1081 Rational Sum (20 分)

  • 题意 :rationnal numbers有理数;numerator/denominator分子/分母;integer part整数部分;fractional part小数部分
  • 题意 :给n个分数,求和,要写成真分数且约分
  • 思路 :初始化a为0,b为1;输出时 :如果分母是1,直接输出整数部分就可以;如果a>b,说明有整数部分和小数部分;pat上分子和分母数据范围是long int,相当于是int,而acwing是long long,如果没有中间那步会溢出,因此分母要变成b和d的最小公倍数,找到b和d的最大公约数,那么分母就是b/最大公约数再*d(原先应该是b *d),分子是…(原先是a * d + b * c),但是分子式子的前半部分是由d/t而不是a/t
  • 语法 :gcd模版;scanf时如果是负数这个符号是在分子上读入的
#include <iostream>

using namespace std;

typedef long long LL;

LL gcd(LL a, LL b)
{
    return b ? gcd(b, a % b) : a;
}

int main()
{
    int n;
    cin >> n;
    
    LL a = 0, b = 1;
    
    for (int i = 0; i < n; i ++ )
    {
        LL c, d;
        scanf("%lld/%lld", &c, &d);
        
        LL t = gcd(c, d);
        c /= t, d /= t;
        
        t = gcd(b, d);
        a = d / t * a + b / t * c;
        b = b / t * d;
        
        t = gcd(a, b);
        a /= t, b /= t;
    }
    
    if (b == 1) cout << a;
    else
    {
        if (a > b) printf("%lld ", a / b), a %= b;
        printf("%lld/%lld", a, b);
    }
    
    return 0;
}

1088 Rational Arithmetic (20 分)

  • 题意 :给两个分数,分别输出加减乘除式子,注意分数要转成真分数,给的可能是假分数
  • 思路 :打印时,先约分,然后判断分母是否为负,然后判断分子是否为负决定是否需要输出两个半括号,然后如果分母是1一种情况,否则要看是否是假分数,假分数时注意是abs,因为这道题会出现分子为负也可能出现分母为负的情况
#include <iostream>

using namespace std;

typedef long long LL;

LL gcd(LL a, LL b)
{
    return b ? gcd(b, a % b) : a;
}

void print(LL a, LL b)
{
    LL t = gcd(a, b);
    a /= t, b /= t;
    
    if (b < 0) a *= -1, b *= -1;
    bool is_minus = a < 0;
    
    if (is_minus) cout << "(";
    
    if (b == 1) cout << a;
    else
    {
        if (abs(a) > b) printf("%lld ", a / b), a = abs(a) % b;
        printf("%lld/%lld", a , b);
    }
    
    if (is_minus) cout << ")";
}

void add(LL a, LL b, LL c, LL d)
{
    print(a, b), cout << " + ", print(c, d), cout << " = ";
    a = a * d + b * c;
    b = b * d;
    print(a, b), cout << endl;
}

void sub(LL a, LL b, LL c, LL d)
{
    print(a, b), cout << " - ", print(c, d), cout << " = ";
    a = a * d - b * c;
    b = b * d;
    print(a, b), cout << endl;
}

void mul(LL a, LL b, LL c, LL d)
{
    print(a, b), cout << " * ", print(c, d), cout << " = ";
    a = a * c;
    b = b * d;
    print(a, b), cout << endl;
}

void div(LL a, LL b, LL c, LL d)
{
    print(a, b), cout << " / ", print(c, d), cout << " = ";
    if (!c) puts("Inf");
    else
    {
        a = a * d;
        b = b * c;
        print(a, b), cout << endl;
    }
}

int main()
{
    LL a, b, c, d;
    scanf("%lld/%lld %lld/%lld", &a, &b, &c, &d);
    
    add(a, b, c, d);
    sub(a, b, c, d);
    mul(a, b, c, d);
    div(a, b, c, d);
    
    return 0;
}

1096 Consecutive Factors (20 分)

  • 题意 :给一数,求最长连续因子
  • 思路 :先枚举起始位置,然后枚举长度;注意有可能只有它本身的情况
  • 语法 : 2 31 2^{31} 231还是int范围;一直循环到连续断了,就直接退出for循环
#include <iostream>
#include <vector>

using namespace std;

int main()
{
    int n;
    cin >> n;
    
    vector<int> res;
    for (int i = 2; i * i <= n; i ++ )
        if (n % i == 0)
        {
            vector<int> seq;
            
            for (int m = n, j = i; m % j == 0; j ++ )
            {
                seq.push_back(j);
                m /= j;
            }
            
            if (seq.size() > res.size()) res = seq;
        }
    
    if (res.empty()) res.push_back(n);
    
    cout << res.size() << endl;
    cout << res[0];
    for (int i = 1; i < res.size(); i ++ ) cout << "*" << res[i];
    
    return 0;
}

1104 Sum of Number Segments (20 分)

在这里插入图片描述

  • 语法 :i和n-i+1都是 1 0 5 10^5 105,相乘有 1 0 10 10^{10} 1010,会超过int,所以那个公式写的时候尽可能把double写到前面,如果写到后面会溢出;(精度?)long double输出时是%Lf
#include <iostream>

using namespace std;

int main()
{
    int n;
    cin >> n;
    
    long double res = 0;
    for (int i = 1; i <= n; i ++ )
    {
        long double x;
        cin >> x;
        
        res += x * i * (n - i + 1);
    }
    
    printf("%.2Lf", res);
    
    return 0;
}

#include <iostream>

using namespace std;

typedef long long ll;

int main()
{
    int n;
    cin >> n;
    
    ll res = 0;
    for (int i = 1; i <= n; i ++ )
    {
        double x;
        cin >> x;
        res += (ll)(1000 * x) * i * (n - i + 1);		// 乘1000放大数字,避免精度的影响,注意括号
    }
    
    printf("%.2lf", res / 1000.0);		// 加上.0可以转化成小数
    
    return 0;
}

1112 Stucked Keyboard (20 分)

  • 题意 :给k和一字符串,字符串中连续出现k次的为坏
  • 思路 :用原字符串判断某个键(数量固定)是否坏;遍历原字符串,每种字符只有三种情况,没坏,坏了但没被输出过,坏了但被输出过,所以不用bool,而用int
#include <iostream>

using namespace std;

const int N = 200;

int st[N];      // 1没坏,0坏了,2输出过

int main()
{
    string s;
    int k;
    cin >> k >> s;
    
    for (int i = 0; i < s.size(); i ++ )
    {
        int j = i + 1;
        while (j < s.size() && s[j] == s[i]) j ++ ;
        int len = j - 1 - i + 1;
        if (len % k) st[s[i]] = 1;
        i = j - 1;      // 因为还要 ++
    }
    
    string res;
    for (int i = 0; i < s.size(); i ++ )
    {
        if (!st[s[i]]) cout << s[i], st[s[i]] = 2;
        
        if (st[s[i]] == 1) res += s[i];
        else
        {
            res += s[i];
            i += k - 1;
        }
    }
            
    cout << endl << res << endl;
    
    return 0;
}

1116 Come on! Let’s C (20 分)

  • 题意 :按排名给id(1e4以内的正整数),根据询问的id判断是否在排名中出现过和是否被询问过,然后是排名第一和排名是否质数
  • 思路 :先把10^4以内的质数先标记一下,用筛法求质数,O(nloglogn);先用过Rank[id]再标记为-1;Rank数组有三种状态,Rank==0代表没有出现过,Rank是-1代表输出过了,Rank是正整数代表正常排名且未输出;st数组有三种状态,0表示筛法时没有被筛过(未被染色)在10 ^4以内也就只有1,1表示是质数,2表示非质数
  • 语法 :注意观察发现输出时必须%04d,像这种固定位数的编号题;
#include <iostream>

using namespace std;

const int N = 1e4 + 10;

int Rank[N], st[N];

void init()
{
    for (int i = 2; i < N; i ++ )
        if (!st[i])
        {
            st[i] = 1;
            for (int j = i * 2; j < N; j += i)
                st[j] = 2;
        }
}

int main()
{
    init();
    
    int n;
    cin >> n;
    for (int i = 1; i <= n; i ++ )
    {
        int id;
        cin >> id;
        Rank[id] = i;
    }
    
    int k;
    cin >> k;
    while (k -- )
    {
        int id;
        cin >> id;
        printf("%04d: ", id);
        
        if (!Rank[id]) puts("Are you kidding?");
        else if (Rank[id] == -1) puts("Checked");
        else
        {
            int t = st[Rank[id]];
            
            if (!t) puts("Mystery Award");
            else if (t == 1) puts("Minion");
            else puts("Chocolate");
            
            Rank[id] = -1;
        }
    }
    
    return 0;
}

1152 Google Recruitment (20 分)

  • 题意 :在给出的一个L(<=1000)位的数中找到第一个K(<10)位的质数
  • 思路 :判断一个数是否是质数,这个题k最大是9位,就是 1 0 9 − 1 10^9-1 1091,不可能把这之间所有质数都找出来,可以用试除法判断,既可以用自然数来试,也可以用质数来试,到 x 1 / 2 x^{1/2} x1/2,如果用自然数来试,最坏情况每次试 ( 1 0 9 ) 1 / 2 (10^9)^{1/2} (109)1/2,差不多3e4,最多1000位,所以3e7,有可能会超时,我们优化一下,试除法的时候不用自然数来试而是用质数来试;费马 :1到n中质数的个数大概是 n / ( l n n ) n/(lnn) n/(lnn),ln(3e4)肯定大于10,也就是可以比自然数效率高10倍以上;所以这道题就是先将1到 ( 1 0 9 ) 1 / 2 (10^9)^{1/2} (109)1/2以内的质数先筛出来,
  • 语法 :这里是先筛质数而不是判断质数,所以1这个特殊情况就不用管了,因为我们只用到primes数组里的东西,st数组不在这题里用;循环条件中的primes[i]
#include <iostream>

using namespace std;

const int N = 4e4;

int primes[N], cnt;
bool st[N];

void init()
{
    for (int i = 2; i < N; i ++ )
        if (!st[i])
        {
            primes[cnt ++ ] = i;
            for (int j = i * 2; j < N; j += i)
                st[j] = true;
        }
}

bool check(string s)
{
    int x = stoi(s);
    for (int i = 0; primes[i] <= x / primes[i]; i ++ )
        if (x % primes[i] == 0)
            return false;
    return true;
}

int main()
{
    init();
    
    int l, k;
    string s;
    cin >> l >> k >> s;
    
    for (int i = 0; i + k <= l; i ++ )
    {
        string ss = s.substr(i, k);
        if (check(ss))
        {
            cout << ss;
            return 0;
        }
    }
    
    cout << 404;
    
    return 0;
}

第八章、动态规划

1007 Maximum Subsequence Sum (25 分)

在这里插入图片描述

  • 题意 :注意最后输出的不是索引而是在那个索引的数
  • 思路 :f为当前的假设开始指针,每一次累加到sum,如果sum大于res,就更新res,开始指针和结束指针;如果sum小于0,说明这段都不要了,那么sum清零,f从下一位开始
#include <iostream>

using namespace std;

const int N = 1e4 + 10;

int num[N];

int main()
{
    int n;
    cin >> n;
    for (int i = 0; i < n; i ++ ) cin >> num[i];
    
    int res = -1e9, sum = 0, from = 0, to = 0, f = 0;
    for (int i = 0; i < n; i ++ )
    {
        sum += num[i];
        if (sum > res) res = sum, from = f, to = i;
        if (sum < 0) sum = 0, f = i + 1;
    }
    
    if (res < 0) res = 0, from = 0, to = n - 1;
    
    cout << res << ' ' << num[from] << ' ' << num[to];
    
    return 0;
}

  • 思路 :dp就是求很多集合中的最优解。状态表示为f[i],集合是所有以i为右端点的区间,属性是区间和的最大值,那么f[i]可以被分为两个区间,一个是区间长度为1,那么区间和的最大值就是w[i],一个是区间长度不为1,那么区间和的最大值就是f[i - 1] + w[i],所以 f [ i ] = m a x ( w [ i ] , f [ i − 1 ] + w [ i ] ) f[i]=max(w[i],f[i-1]+w[i]) f[i]=max(w[i],f[i1]+w[i]),也就是 f [ i ] = w [ i ] + m a x ( 0 , f [ i − 1 ] ) f[i]=w[i]+max(0, f[i-1]) f[i]=w[i]+max(0,f[i1]),由于这里f[i]只会用到f[i-1],就发现其实f数组不需要开,可以用一个变量来存
#include <iostream>

using namespace std;

const int N = 1e4 + 10;

int w[N];

int main()
{
    int n;
    cin >> n;
    for (int i = 1; i <= n; i ++ ) cin >> w[i];
    
    int res = -1, l, r;
    for (int i = 1, sum = -1, start; i <= n; i ++ )
    {
        if (sum < 0) sum = 0, start = i;
        sum += w[i];
        if (sum > res)
        {
            res = sum;
            l = w[start], r = w[i];
        }
    }
    
    if (res < 0) res = 0, l = w[1], r = w[n];
    
    cout << res << ' ' << l << ' ' << r;
    
    return 0;
}

第九章、哈希表

1120 Friend Numbers (20 分)

在这里插入图片描述

  • 思路 :什么数据结构可以让我们既判重又排序呢?其实不用哈希表而用set会更好,可以少一步排序
  • 语法 :set默认从小到大排序;空格输出新方法(这题如果不判空格会wa)
#include <iostream>
#include <set>

using namespace std;

int main()
{
    int n;
    cin >> n;
    
    set<int> se;
    
    while (n -- )
    {
        int x;
        cin >> x;
        int s = 0;
        while (x) s += x % 10, x /= 10;
        se.insert(s);
    }
    
    cout << se.size() << endl;;
    
    bool is_first = true;
    for (auto x : se)
    {
        if (is_first) is_first = false;
        else cout << ' ';
        cout << x;
    }
    
    return 0;
}

1144 The Missing Number (20 分)

在这里插入图片描述

  • 思路 :这里用while比用for方便,就是找一个从1开始连续增加的数字
  • 语法 :set的insert和find均为 O ( l o g n ) O(logn) O(logn),count为 O ( k + l o g n ) O(k+logn) O(k+logn)
#include <iostream>
#include <unordered_set>

using namespace std;

int main()
{
    int n;
    cin >> n;
    
    unordered_set<int> se;
    
    while (n -- )
    {
        int x;
        cin >> x;
        se.insert(x);
    }
    
    int res = 1;
    
    while (se.count(res)) res ++ ;
    cout << res;
    
    return 0;
}

第十章、并查集

第十一章、模拟

1008 Elevator (20 分)

在这里插入图片描述

  • 思路 :last可能等于cur,而无论是否相等,res都是+5的
#include <iostream>

using namespace std;

int main()
{
    int n;
    cin >> n;
    
    int res = 0, last = 0;
    
    while (n -- )
    {
        int cur;
        cin >> cur;
        
        if (cur > last) res += 6 * (cur - last);
        else res += 4 * (last - cur);
        res += 5;
        
        last = cur;
    }
    
    cout << res;
    
    return 0;
}

1011 World Cup Betting (20 分)

在这里插入图片描述

  • 思路 :三次,每次将输入的三个数中最大的的对应字母输出,最后再乘上最大的数
#include <iostream>

using namespace std;

int main()
{
    double res = 1;
    double w, t, l;
    
    for (int i = 0; i < 3; i ++ )
    {
        cin >> w >> t >> l;
        double x = max(w, max(t, l));
        
        if (w == x) cout << "W ";
        else if (t == x) cout << "T ";
        else cout << "L ";
        res *= x;
    }
    
    printf("%.2lf", (res * 0.65 - 1) * 2);

	return 0;
}

1031 Hello World for U (20 分)

在这里插入图片描述

  • 题意 :输出U型字符串,满足 n 1 = = n 3 , n 1 + n 2 + n 3 − 2 = = n n_1==n_3,n_1+n_2+n_3-2==n n1==n3,n1+n2+n32==n,且 n 1 n_1 n1 n 2 n_2 n2尽可能近
  • 思路 :根据等式,一个 n 1 n_1 n1一定对应 n 2 和 n 3 n_2和n_3 n2n3,所以直接令 n 1 = ( n + 2 ) / 3 n_1=(n+2)/3 n1=(n+2)/3就是尽可能近的结果,那么得到了 n 1 , n 2 , n 3 n_1,n_2,n_3 n1,n2,n3;剩下的就是在一个矩阵中填入字符了,分为三个部分,注意第三个部分是从下往上填的;输出矩阵时,如果 g [ i ] [ j ] = = 0 g[i][j] ==0 g[i][j]==0,说明没有在这个位置填过(注意不是字符0),就输出空格。
  • 语法 :字符矩阵中没有被填过的部分如何表示。
#include <iostream>

using namespace std;

char g[85][85];

int main()
{
    string str;
    cin >> str;
    
    int n = str.size();
    int n1 = (n + 2) / 3;
    int n3 = n1, n2 = n - n1 - n3 + 2;
    
    int k = 0;
    for (int i = 0; i < n1; i ++ ) g[i][0] = str[k ++ ];
    for (int i = 1; i <= n2 - 2; i ++ ) g[n1 - 1][i] = str[k ++ ];
    for (int i = n1 - 1; i >= 0; i -- ) g[i][n2 - 1] = str[k ++ ];
    
    for (int i = 0; i < n1; i ++ )
    {
        for (int j = 0; j < n2; j ++ )
            if (g[i][j]) cout << g[i][j];
            else cout << ' ';
        cout << endl;
    }

    return 0;
}

1041 Be Unique (20 分)

在这里插入图片描述

  • 题意 :找到输入的数中第一个只出现过一次的数
  • 思路 :先用一维数组存下按顺序输入的数,再套一个一维数组存数对应出现的次数,那么遍历第一个数组首先找到次数为1的数就可以直接break了
#include <iostream>

using namespace std;

const int N = 1e5 + 10;

int a[N], c[N];

int main()
{
    int n;
    cin >> n;
    for (int i = 0; i < n; i ++ )
    {
        cin >> a[i];
        c[a[i]] ++ ;
    }
    
    for (int i = 0; i < n; i ++ )
        if (c[a[i]] == 1)
        {
            cout << a[i];
            return 0;
        }
    
    puts("None");
    return 0;
}

1042 Shuffling Machine (20 分)

在这里插入图片描述

  • 思路 :牌号的规律,先不管字母,就是1-54号的牌,然后再根据函数对应打印;最后结果要按照位序打印出对应位序上的数,所以想到用一个一维数组记录当前位序i对应的数,因为要经过k次洗牌,且不能覆盖当前的,想到再开一个一维数组记录上一次位序i对应的数。
  • 语法 :memcpy函数在cstring头文件中
#include <iostream>
#include <cstring>

using namespace std;

const int N = 60;

int p[N], q[N], w[N];

void print(int x)
{
    if (x <= 13) cout << 'S' << x;
    else if (x <= 26) cout << 'H' << x - 13;
    else if (x <= 39) cout << 'C' << x - 26;
    else if (x <= 52) cout << 'D' << x - 39;
    else cout << 'J' << x - 52;
}

int main()
{
    int k;
    cin >> k;
    
    for (int i = 1; i <= 54; i ++ ) cin >> q[i];
    for (int i = 1; i <= 54; i ++ ) p[i] = i;
    
    while (k -- )
    {
        memcpy(w, p, sizeof p);
        for (int i = 1; i <= 54; i ++ ) p[q[i]] = w[i];
    }
    
    for (int i = 1; i <= 54; i ++ )
    {
        print(p[i]);
        if (i != 54) cout << ' ';
    }
}

1054 The Dominant Color (20 分)

在这里插入图片描述

  • 题意 :找到n * m的矩阵中出现次数超过n * m / 2的并输出,直接模拟即可。
#include <iostream>
#include <unordered_map>

using namespace std;

int main()
{
    int n, m;
    cin >> m >> n;
    unordered_map<int, int> cnt;
    
    for (int i = 0; i < n; i ++ )
        for (int j = 0; j < m; j ++ )
        {
            int x;
            cin >> x;
            if ( ++ cnt[x] > n * m / 2)
            {
                cout << x;
                break;
            }
        }
    
    return 0;
}

1065 A+B and C (64bit) (20 分)

在这里插入图片描述

  • 思路 :考察C++中整数在计算机中表示的方法;数据范围是所有的long long范围,所以ab相加可能会溢出,而溢出情况只可能有两种,一正一负不可能溢出,不溢出直接运算就可以;如果是第一种情况的溢出,由于C是范围内的数,所以一定大于c,第二种情况则反之
  • 最高位是0是非负数,是1是负数;表示负数就是正数所有位取反再加一(~x+1);大于等于0的范围是 0 到 2 63 − 1 0到2^{63}-1 02631,负数是 − 2 63 到 − 1 -2^{63}到-1 2631;所以两个正数相加溢出的范围是 2 63 到 2 64 − 2 2^{63}到2^{64}-2 2632642,那么最高位一定是1,所以两个正数相加溢出一定变成负数。
  • 语法 :long long 对应%lld
#include <iostream>

using namespace std;

typedef long long LL;

bool check(LL a, LL b, LL c)
{
    LL d = a + b;
    if (a >= 0 && b >= 0 && d < 0) return true;
    if (a < 0 && b < 0 && d >= 0) return false;
    return a + b > c;
}

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

1069 The Black Hole of Numbers (20 分)

在这里插入图片描述

  • 题意 :直到得到结果是0或者6174才停下,这个时候的式子也是要输出的;注意这道题分别获得两个数的时候无论原来的数是几位,后来都是获得两个四位数,也就是四次*10
  • 语法 :sort默认从小到大;函数可以返回vector容器;sort在algorithm头文件中; r e v e r s e reverse reverse在algorithm头文件中;dowhile。
#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

vector<int> get(int n)
{
    int nums[4];
    for (int i = 0; i < 4; i ++ )
    {
        nums[i] = n % 10;
        n /= 10;
    }
    
    sort(nums, nums + 4);
    int a = 0;
    for (int i = 0; i < 4; i ++ ) a = a * 10 + nums[i];
    
    reverse(nums, nums + 4);
    int b = 0;
    for (int i = 0; i < 4; i ++ ) b = b * 10 + nums[i];
    
    return {b, a};
}

int main()
{
    int n;
    cin >> n;
    
    do
    {
        auto t = get(n);
        printf("%04d - %04d = %04d\n", t[0], t[1], t[0] - t[1]);
        
        n = t[0] - t[1];
    } while (n && n != 6174);
        
    return 0;
}

1092 To Buy or Not to Buy (20 分)

在这里插入图片描述

  • 思路 :多多少和少多少相互之间是没有影响的,如果少多少是0才输出多多少
  • 语法 :unordered_map的遍历
#include <iostream>
#include <unordered_map>

using namespace std;

int main()
{
    string a, b;
    cin >> a >> b;
    
    unordered_map<char, int> S;
    for (auto c : a) S[c] ++ ;
    for (auto c : b) S[c] -- ;
    
    int sp = 0, sn = 0;
    for (auto item : S)
        if (item.second > 0) sp += item.second;
        else sn -= item.second;
    
    if (sn) printf("No %d", sn);
    else printf("Yes %d", sp);
    
    return 0;
}

1128 N Queens Puzzle (20 分)

在这里插入图片描述

  • 题意 :diagonal对角线
  • 语法 :一组样例多组输入的题目不要随意break!!利用数组的坐标系去看的话,也就是->y,|V为x,得知反对角线是y-x是个定值(y=x+b,与寻常坐标系反),而正对角线是y+x是个定值
#include <iostream>
#include <cstring>

using namespace std;

const int N = 1e3 + 10;

bool row[N], dg[N * 2], udg[N * 2];

int main()
{
    int T;
    cin >> T;
    
    while (T -- )
    {
        memset(row, 0, sizeof row);
        memset(dg, 0, sizeof dg);
        memset(udg, 0, sizeof udg);
        
        int n;
        cin >> n;
        
        bool success = true;
        
        for (int y = 1; y <= n; y ++ )
        {
            int x;
            cin >> x;
            
            if (row[x] || dg[y + x] || udg[y - x + n]) success = false;
            row[x] = dg[y + x] = udg[y - x + n] = true;
        }
        
        if (success) puts("YES");
        else puts("NO");
    }
    
    return 0;
}

1132 Cut Integer (20 分)

在这里插入图片描述

  • 语法 :当将任何变量放在“/‘后面或者”%“后面都要注意它是否为0
#include <iostream>

using namespace std;

int main()
{
    int T;
    cin >> T;
    
    while (T -- )
    {
        string s;
        cin >> s;
        
        int len = s.size() / 2;
        int left = stoi(s.substr(0, len));
        int right = stoi(s.substr(len, len));
        int n = stoi(s);
        
        if (left * right && n % (left * right) == 0) puts("Yes");
        else puts("No");
    }
    
    return 0;
}

1140 Look-and-say Sequence (20 分)

在这里插入图片描述

  • 思路 :问的是序列中第n个数,所以循环的是n-1次;找字符串中连续的次数的方法
#include <iostream>

using namespace std;

int main()
{
    int d, n;
    cin >> d >> n;
    string cur = to_string(d);
    
    for (int k = 0; k < n - 1; k ++ )
    {
        string next;
        
        for (int i = 0; i < cur.size();)
        {
            int j = i + 1;
            while (j < cur.size() && cur[i] == cur[j]) j ++ ;
            next += cur[i] + to_string(j - i);
            i = j;
        }
        
        cur = next;
    }
    
    cout << cur;
    
    return 0;
}

第十二章、贪心

第十三章、链表

第十四章、基础算法与数据结构

1046 Shortest Distance (20 分)

在这里插入图片描述

  • 思路 :前缀和
  • 语法 : s w a p 和 m i n 和 m a x swap和min和max swapminmax只需要 i o s t r e a m iostream iostream头文件;while里面如果要使得结尾无空行,判断条件是m!=0而不是m!=1
#include <iostream>

using namespace std;

const int N = 1e5 + 10;

int s[N];

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

1148 Werewolf - Simple Version (20 分)

在这里插入图片描述

  • 题意 :in ascending order 升序
  • 思路 :以两个狼人为假设(枚举时j为i+1,不重不漏),如果谎话数不是1就no,然后再统计总的谎话数如果不是2就no;谎话数的判断,传入第几个人以及两个狼人分别是谁这三个参数,如果这个人判断的是人类,…,如果判断的是狼人…。
#include <iostream>

using namespace std;

const int N = 110;

int q[N];

int judge(int k, int i, int j)      // 1为假话,0为真话
{
    int t = q[k];
    
    if (t > 0)
    {
        if (t == i || t == j)
            return 1;
        return 0;
    }
    
    t = -t;
    if (t == i || t == j) return 0;
    return 1;
}

int main()
{
    int n;
    cin >> n;
    for (int i = 1; i <= n; i ++ ) cin >> q[i];
    
    for (int i = 1; i <= n; i ++ )
        for (int j = i + 1; j <= n; j ++ )
        {
            int s = 0;
            s = judge(i, i, j) + judge(j, i, j);
            if (s != 1) continue;
            
            s = 0;
            for (int k = 1; k <= n; k ++ )
                s += judge(k, i, j);
            
            if (s != 2) continue;
            
            cout << i << ' ' << j;
            return 0;
        }
    
    cout << "No Solution";
    
    return 0;
}

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值