PAT – ADVANCED – 20POINTS (UPDATING)

进制转换类

常用 除余法

A1001 取进制各位

思路1 %10得末位数,/10前移一位,由此得到逆序各位数
思路2 分段输出左对齐补0,$\scriptsize [10^6]=n/1000000,[10^3,10^6]=n/1000 \mod 1000,[0,10^3]=n \mod 1000$

int main()
{
    vector<char> v;
    int a, b;
    scanf("%d %d", &a, &b);

    a += b;
    if(a < 0) { putchar('-'); a = -a; }
    if(a == 0) v.push_back('0');

    for(int i = 1; a; i++) {
        v.push_back('0' + a % 10);
        a /= 10;
        if(a && i % 3 == 0) v.push_back(',');
    }

    for(int i = v.size() - 1; i >= 0; i--)
        putchar(v[i]);
    putchar('n');
    return 0;
}

A1005 取进制各位、大整数字符串存储

注意0特殊情况输出的是”zero”

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

int main() {
    string chn[] = {"zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine"};
    vector<int> v;
    int sum = 0, i;
    char s[101];

    scanf("%s", s);
    for (int i = 0; s[i]; i++)
        sum += s[i] - '0';

    while (sum) {
        v.push_back(sum % 10);
        sum /= 10;
    }

    for (i = v.size() - 1; i > 0; i--)
        printf("%s ", chn[v[i]].c_str());

    if(i == -1) printf("zeron");
    else printf("%sn", chn[v[0]].c_str());

    return 0;
}

A1008 记录循环旧值

每次循环记录旧值pre,可迭代入新一轮计算cur

#include <iostream>
using namespace std;

int main() {
    int N, pre = 0, cur;
    long long sum = 0;
    scanf("%d", &N);

    while (N--) {
        scanf("%d", &cur);
        if (cur >= pre) sum += 6 * (cur - pre) + 5;
        else sum += 4 * (pre - cur) + 5;
        pre = cur;
    }

    printf("%lldn", sum);

    return 0;
}

A1011 求取最大值

无需开O(n)数组记录,仅需一个变量迭乘

#include <iostream>
using namespace std;

int main() {
    double m, num, r = 1.0;
    char n[] = {'W', 'T', 'L'};
    int id;

    for(int i = 0; i < 3; i++) {
        m = __DBL_MIN__;
        for(int j = 0; j < 3; j++) {
            scanf("%lf", &num);
            if(m < num) {
                id = j;
                m = num;
            }
        }
        r *= m;
        printf("%c ", n[id]);
    }

    printf("%.2fn", (0.65 * r - 1) * 2);

    return 0;
}

A1015 素数判断、进制转换

大端k进制数取得:先余k后除k即可得到
判断质数:问题规模 $\scriptsize \lt 10^5$,逐项除余即可
输入格式:先满足第一个数合法,再读入另一个数计算

#include <iostream>
using namespace std;

int toReverseDecimal(int n, int r) {
    int num = 0;
    while (n) {
        num = num * r + n % r;
        n /= r;
    }
    return num;
}

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

int main() {
    int N, D;
    while (~scanf("%d", &N)) {
        if (N < 0) break;
        scanf("%d", &D);
        if (isPrime(N)) {
            N = toReverseDecimal(N, D);
            if (isPrime(N)) printf("Yesn");
            else printf("Non");
        }
        else printf("Non");
    }
    return 0;
}

A1019 进制转换、双指针

注意细节:指针累加记录至末尾时多一,访问末尾索引需减一

#include <iostream>
using namespace std;

int main() {
    int num[31];
    bool isP = true;
    int t = 0, h = 0, t1;
    long long N, b;
    scanf("%lld%lld", &N, &b);

    while (N) {
        num[t++] = N % b;
        N /= b;
    }

    t -= 1;
    t1 = t;
    while (h < t)
        if (num[h++] != num[t--])
            isP = false;

    if (isP)        printf("Yesn");
    else            printf("Non");
    while (t1 > 0)  printf("%d ", num[t1--]);
    printf("%dn", num[0]);

    return 0;
}

A1027 进制转换

本题仅有两位,先除后余,无需倒序处理

#include <iostream>
using namespace std;

char R[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C'};

int main() {
    int a, b, c;
    scanf("%d%d%d", &a, &b, &c);
    putchar('#');
    printf("%c%c", R[a / 13], R[a % 13]);
    printf("%c%c", R[b / 13], R[b % 13]);
    printf("%c%c", R[c / 13], R[c % 13]);
    return 0;
}

A1058 变进制数

此题注意自身叠加运算导致某数改变,后续重用该数时已不是原值,应使用中间变量保存结果

#include<iostream>
using namespace std;

int main() {
    int ga, sa, ka;
    int gb, sb, kb;
    int of;
    scanf("%d.%d.%d %d.%d.%d", &ga, &sa, &ka, &gb, &sb, &kb);
    of = (ka + kb) / 29;
    ka = (ka + kb) % 29;

    kb = sa + sb + of;
    sa = kb % 17;
    of = kb / 17;

    ga = ga + gb + of;

    printf("%d.%d.%d", ga, sa, ka);
    return 0;
}

大整数运算

采用 字符串读入,逐位运算
常见 竖式计算模拟,记录借位进位即可

A1023 乘法模拟

乘法模拟:从低位到高位逐位乘并累加进位
进位处理:注意最高位进位会导致长度增加
正确性验证:原始各位数字计数num与结果各位数字num[r[i]]计数比对

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

int main() {
    char s[21];
    scanf("%s", s);
    int num[10] = {0}, r[21] = {0};
    int i, j = 0, len = strlen(s);

    for(i = len - 1; i >= 0; i--) {
        int id = s[i] - '0';
        int db = id << 1;

        r[j] += db;
        if(r[j] >= 10) r[j] -= 10;
        r[j + 1] = (db >= 10);

        num[id]++;
        num[r[j]]--;
        j++;
    }

    if(r[j])  num[r[j]]--;
    else      j--;
    i = j;

    for(; j >= 0; j--)
        if(num[r[j]]) {
            printf("Non");
            break;
        }
    if(j == -1)     printf("Yesn");
    while(i >= 0)   printf("%d", r[i--]);
}

图形输出

图形输出题主要是寻找序号与输出之间的规律

A1031 找规律、双指针

枚举发现规律:图形高度h = (l + 2) / 3,中央空格数m = l – 2 * h;
对称输出:输出{s[i],s[n-i-1]},或用双指针法{s[i++],s[j–]}

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

int main()
{
    int h, m, l, i, j;
    char s[81];
    scanf("%s", s);

    l = strlen(s);
    h = (l + 2) / 3;
    m = l - 2 * h;

    for (i = 0, j = l - 1; i <= j; i++, j--) {
        if (h > 1) {
            putchar(s[i]);
            for (int k = 0; k < m; k++)
                putchar(' ');
            h--;
            putchar(s[j]);
            putchar('n');
        }
        else while(i <= j) putchar(s[i++]);
    }
    return 0;
}

哈希散列

主要是stl::unordered_map的使用

A1035 哈希表存取

判断并修改:遍历字符串使用哈希表查找替换
修改个数计数:初始num=0,每一字符串判断发生修改++num即为修改个数
输出结果集:若修改下次读入pswd[++num],若未修改下次覆盖读入pswd[num],结果集范围[0,num-1]

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

int main() {
    char user[1000][11], pswd[1000][11], cur;
    unordered_map<char, char> map;
    int total, i, add, num = 0;
    map['0'] = '%';
    map['O'] = 'o';
    map['1'] = '@';
    map['l'] = 'L';

    scanf("%d", &total);

    while (~scanf("%s %s", user[num], pswd[num])) {
        i = 0; add = 0;
        while (pswd[num][i]) {
            cur = pswd[num][i];
            if (map.find(cur) != map.end()) {
                pswd[num][i] = map[cur];
                add = 1;
            }
            i++;
        }
        num += add;
    }

    if (num > 0) {
        printf("%dn", num);
        for (int j = 0; j < num; j++)   printf("%s %sn", user[j], pswd[j]);
    }
    else if (total == 1)    printf("There is 1 account and no account is modifiedn");
    else                    printf("There are %d accounts and no account is modifiedn", total);

    return 0;
}

A1041 散列计数

题意理解:筛出的是只出现一次,且按输入序首次出现的数字
保存输入序:按输入序检索需按序保存数字个数N,最大1e5+1
哈希表大小:数字范围[1,1e4],需开1e4+1

#include <iostream>
using namespace std;

int main() {
    int map[10001] = {0}, num[100001] = {0};
    int N, i;
    scanf("%d", &N);

    for (i = 0; i < N; i++) {
        scanf("%d", &num[i]);
        map[num[i]]++;
    }

    for (i = 0; i < N; i++) {
        if (map[num[i]] == 1) {
            printf("%dn", num[i]);
            return 0;
        }
    }
    printf("Nonen");

    return 0;
}

A1050 散列去重

#include <iostream>
using namespace std;
int main() {
    int i = -1, s2[128] = {0};
    char s1[10001], c;

    while ((c = getchar()) != 'n') s1[++i] = c;
    s1[++i] = '';

    while ((c = getchar()) != 'n') s2[c]++;
    i = -1;

    while (s1[++i]) if (!s2[s1[i]]) putchar(s1[i]);
    putchar('n');
    return 0;
}

字符串处理

scanf读入整行时可能以空格为分隔符,改为cstio::gets()或逐字符读取
逐字符读取时要在读取末尾手动添加”标明字符串结束,以防未初始化数组随机值影响

循环结构

A1061 循环细节

①不满足条件而继续循环,条件应置于循环内部,否则将直接退出循环
②区分break在条件分支内和分支后
③此题较坑的部分是隐含范围”MON-SUN”对应的范围为”A-G”

#include <iostream>
using namespace std;

int main() {
    char s1[61], s2[61], s3[61], s4[61];
    char *day[7] = {"MON", "TUE", "WED", "THU", "FRI", "SAT", "SUN"};
    int i;
    scanf("%s%s%s%s", s1, s2, s3, s4);

    for (i = 0; s1[i] && s2[i]; i++)
        if (s1[i] == s2[i] && s1[i] >= 'A' && s1[i] <= 'G')
            break;
    printf("%s ", day[s1[i] - 'A']);

    for (++i; s1[i] && s2[i]; i++)
        if (s1[i] == s2[i]) {
            if (s1[i] >= 'A' && s1[i] <= 'N')      printf("%02d:", s1[i] - 'A' + 10);
            else if (s1[i] >= '0' && s1[i] <= '9') printf("%02d:", s1[i] - '0');
            else continue;
            break;
        }

    for (i = 0; s3[i] && s4[i]; i++)
        if (s3[i] == s4[i] && ((s3[i] >= 'a' && s3[i] <= 'z') || (s3[i] >= 'A' && s3[i] <= 'Z')))
            break;#include <iostream>
using namespace std;

    int main() {
        int t = 1;
        bool isAbove = false;
        long long a, b, c, r;
        while (getchar() != 'n') ;
        while (~scanf("%lld%lld%lld", &a, &b, &c)) {
            r = a + b;
            if (a > 0 && b > 0 && r < 0) isAbove = true;
            else if (a < 0 && b < 0 && r >= 0) isAbove = false;
            else if (r > c) isAbove = true;
            else isAbove = false;

            if (isAbove) printf("Case #%d: truen", t);
            else printf("Case #%d: falsen", t);
            t++;
        }

        return 0;
    }
    printf("%02dn", i);

    return 0;
}

类型边界

A1065 超限处理

①特殊处理超范围情况,其余正常判断
long long 类型表示范围 $\scriptsize [-2^{63},2^{63}-1]$
上限溢出时 $\scriptsize a+b \in [2^{63},2^{64}-2]$,计算结果 $\scriptsize \% 64 = [-2^{63},-2]$
下限溢出时 $\scriptsize a+b \in [-2^{64},-2^{63}-1]$,计算结果 $\scriptsize \% 64 = [-2^{63}-1,0]$
②用字符串模拟竖式加减法,并比较结果

#include <iostream>
using namespace std;

int main() {
    int t = 1;
    bool isAbove = false;
    long long a, b, c, r;
    while (getchar() != 'n') ;
    while (~scanf("%lld%lld%lld", &a, &b, &c)) {
        r = a + b;
        if (a > 0 && b > 0 && r < 0) isAbove = true;
        else if (a < 0 && b < 0 && r >= 0) isAbove = false;
        else if (r > c) isAbove = true;
        else isAbove = false;

        if (isAbove) printf("Case #%d: truen", t);
        else printf("Case #%d: falsen", t);
        t++;
    }

    return 0;
}

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注

©2018-2024 Howell版权所有 备案号:冀ICP备19000576号