PAT做题总结1

本人初次接触PAT,对于题目的理解尚浅,此篇主要记录本人的做题笔记,还望各位大佬多多指教。

连续因子

题目大意:
输入一行:N(N < 2 ^ 31);
输出:
第一行:最长连续因子的个数
第二行:因子1*因子2 *…因子k
例:
输入 630
输出:
3
5 * 6 * 7

敲黑板的重点

  1. N < 2 * 31, 则这个值位于 12的阶乘到13的阶乘之间,所以最大的值应该是12个数连续相乘;基本常识吧
  2. 因为要求最长连续因子个数,我们从2开始枚举,用n % sum 来判断是否退出循环。
  3. 在有两个及以上的数连乘中,因数的最大上限为sqrt(N) + 1;
  4. 一个标志,到最后输出的时候,判断即可。
#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
long long num, temp;
int main(void){
    cin >> num;
    int first = 0, len = 0, maxn = int (sqrt(num)) + 1;
    for(int i = 2; i <= maxn; i ++){
        int j;
        temp = 1;
        for(j = i; j <= maxn; j ++){
            temp *= j;
            if(num % temp != 0) break;
        }
        if(j - i > len){
            len = j - i;
            first = i;
        }
    }
    if(first == 0) cout << 1 << endl << num;
    else{
        cout << len << endl;
        for(int i = 0; i < len; i ++){
            cout << first + i;
            if(i != len - 1) cout << "*";
        }
        cout << endl;
    }
    return 0;
}

N个数求和

在这里插入图片描述
输入1:
2
4/3 2/3
输出:
2

分析

  1. 每两个数相加,分母通分(辗转相除法求最大公因数,再得出最小公倍数)分子按比例相加,每次运行完后化成最简分数。
  2. 仅整数部分输出整数,整数部分为0只输出分数部分,但0特殊,输出0;
  3. 思考 输入一个数:-3/2, 输出?
    输出 -1 1/2 。(-3 / 2 = -1)
#include <iostream>
#include <algorithm>
#define ll long long
using namespace std;
ll gcd(ll a, ll b){  //求出最大公因数
    return a % b == 0 ? b : gcd(b, a % b);
}
void solve(ll &a, ll &b){
    ll yue = gcd(a, b);
    if(yue){
        a /= yue;
        b /= yue;
    }
}

int main(void){
    int n;
    ll x, y, fz = 0, fm = 1;
    scanf("%d", &n);
    for(int i = 0; i < n; i ++){
        scanf("%lld/%lld", &x, &y);
        ll yue = gcd(fm, y), bei = fm / yue * y;
        fz = fz * (bei / fm) + x * (bei / y);
        fm = bei;
        solve(fz, fm);
    }
    if(fz == 0){
        printf("0\n");
    }
    else if(abs(fz) < abs(fm)){
        if(fz * fm < 0) cout << "-";
        printf("%lld/%lld\n", abs(fz), abs(fm));
    }
    else{
        printf("%lld", fz / fm);
        if(fz % fm){
            printf(" %lld/%lld", abs(fz%fm), abs(fm));
        }
        printf("\n");
    }
    return 0;
}

特立独行的幸福

题目大意

对一个十进制数的各位数字做一次平方和,称作一次迭代。如果一个十进制数能通过若干次迭代得到 1,就称该数为幸福数。1 是一个幸福数。此外,例如 19 经过 1 次迭代得到 82,2 次迭代后得到 68,3 次迭代后得到 100,最后得到 1。则 19 就是幸福数。显然,在一个幸福数迭代到 1 的过程中经过的数字都是幸福数,它们的幸福是依附于初始数字的。例如 82、68、100 的幸福是依附于 19 的。而一个特立独行的幸福数,是在一个有限的区间内不依附于任何其它数字的;其独立性就是依附于它的的幸福数的个数。如果这个数还是个素数,则其独立性加倍。例如 19 在区间[1, 100] 内就是一个特立独行的幸福数,其独立性为 2×4=8。
另一方面,如果一个大于1的数字经过数次迭代后进入了死循环,那这个数就不幸福。例如 29 迭代得到 85、89、145、42、20、4、16、37、58、89、…… 可见 89 到 58 形成了死循环,所以 29 就不幸福。
本题就要求你编写程序,列出给定区间内的所有特立独行的幸福数和它的独立性。
输入格式:
输入在第一行给出闭区间的两个端点:1<A<B≤10
​4
​​。
输出格式:
按递增顺序列出给定闭区间 [A,B] 内的所有特立独行的幸福数和它的独立性。每对数字占一行,数字间以 1 个空格分隔。
如果区间内没有幸福数,则在一行中输出 SAD。
输入样例 1:
10 40
输出样例 1:
19 8
23 6
28 3
31 4
32 3
注意:样例中,10、13 也都是幸福数,但它们分别依附于其他数字(如 23、31 等等),所以不输出。其它数字虽然其实也依附于其它幸福数,但因为那些数字不在给定区间 [10, 40] 内,所以它们在给定区间内是特立独行的幸福数。
输入样例 2:
110 120
输出样例 2:
SAD

分析

  1. 明确幸福数的定义,当A经过若干次循环得到B,即使B经过有限次循环也能得到1,B也不是幸福数。跟A、B大小无关
  2. 代码中ans集合作用:存储答案,当不是幸福数时要及时删除。
  3. all存储所有的初始数和其过成数。 若一个数是之前判断过的一个数,这数一定不是幸福数。
  4. s小集合,判断是否出现循环,若出现直接判断非幸福数。
  5. s.size()就是对应的幸福指数。
  6. map构成了一个幸福数和其指数的一个映射。
  7. 输出很棒,记得学习。
#include <bits/stdc++.h>
using namespace std;
int A, B;
map<int, int> mp;
set<int> ans, all;
int happy(int x){
    if(all.count(x)) return 0;
    else all.insert(x);
    set<int>s;
    int sum = 0;
    while(x){
        sum += (x % 10) * (x % 10);
        x /= 10;
    }
    if(ans.count(sum)) ans.erase(sum);
    s.insert(sum);
    all.insert(sum);
    while(sum != 1){
        auto t = 0;
        while(sum){
            t += (sum % 10) * (sum % 10);
            sum /= 10;
        }
        sum = t;
        all.insert(sum);
        if(ans.count(sum)) ans.erase(sum);
        if(!s.count(sum)) s.insert(sum);
        else return 0;
    }
    return s.size();
}
int primes(int x){
    if(x < 2) return 1;
    for(int i = 2; i * i <= x; i ++){
        if(x % i == 0) return 1;
    }
    return 2;
}

int main(void){
    cin >> A >> B;
    for(int i = A; i <= B; i ++){
        int n1 = happy(i);
        if(n1 == 0) continue;
        n1 *= primes(i);
        mp[i] = n1;
        ans.insert(i);
    }
    if(ans.size()) for(auto x:ans) cout << x << " " << mp[x]<<endl;
    else puts("SAD");
    return 0;
}

估值一亿的AI核心代码 (主要为字符串的处理)

在这里插入图片描述

C中 isalnum函数

isalnum(c) 如果c是一个数字或一个字母,则该函数返回非0值,否则返回0;
代码开头#include <ctype.h>
本题并未拿满分,只是18分。但重在体会代码中的stringstream ss(s) 等。

#include <bits/stdc++.h>
using namespace std;
string str[1005];
int main(void){
    int n;
    cin >> n;
    getchar();
    string s;
    while(n --){
        getline(cin, s);
        int cnt = 0;
        cout << s << endl << "AI:";
        //处理原始字符串,使得大小写、个别标点变化完成;
        for(int i = 0; i < s.size(); i ++){
            if(isalnum(s[i])){
                if(s[i] >= 'A' && s[i] <= 'Z' && s[i] != 'I'){
                    s[i] = s[i] + 32;
                }
            }
            else{
                s.insert(i, " ");//对标点的提出
                i ++;
            }
            if(s[i] == '?') s[i] = '!';
        }
        stringstream ss(s);
        //效果就是把含多个空格的字符串, 以空格为分割点,变成若干的小型字符串(单词或标点)
        while(ss >> s){
            str[cnt ++] = s;
           // cout<<str[cnt - 1] << endl;
        }

        if(isalnum(str[0][0])) cout <<" ";//开头若是标点,不能输出空格;
        for(int i = 0; i < cnt; i ++){
            if(!isalnum(str[i][0])) cout << str[i];//是个标点, 其前边不能输出空格。
            else if((str[i] == "can" || str[i] == "could") && str[i + 1] == "you"){
                if(i != 0) cout << " I " << str[i];
                else cout << "I " << str[i];
                i ++;
            }
            else if((str[i] == "can" || str[i] == "could") && isalnum(str[i + 1][0]) == 0 && str[i + 2] == "you"){
                if(i != 0) cout << " I" << str[i + 1] << " "<< str[i];
                else cout << "I" << str[i + 1] << " " << str[i];
                i ++;
                i ++;
            }
            else if(str[i] == "I" || str[i] == "me"){
                if(i != 0) cout << " you";
                else cout <<"you" ;
            }
            else{
                if(i != 0) cout << " "<<str[i];
                else cout << str[i];
            }
        }
        cout << endl;
    }
    return 0;

}

深入虎穴(距根节点最远编号)

已知情报藏在一个地下迷宫里,迷宫只有一个入口,里面有很多条通路,每条路通向一扇门。每一扇门背后或者是一个房间,或者又有很多条路,同样是每条路通向一扇门…… 他的手里有一张表格,是其他间谍帮他收集到的情报,他们记下了每扇门的编号,以及这扇门背后的每一条通路所到达的门的编号。007 发现不存在两条路通向同一扇门。

内线告诉他,情报就藏在迷宫的最深处。但是这个迷宫太大了,他需要你的帮助 —— 请编程帮他找出距离入口最远的那扇门。

输入首先在一行中给出正整数 N(<10^​5​​ ),是门的数量。最后 N 行,第 i 行(1≤i≤N)按以下格式描述编号为 i 的那扇门背后能通向的门.每行第一个数字 k 表示有几个能通向的数字。
输出距离入口最远的那扇门的编号。

思路

  1. 一个book数组,标记所有点能达到的点,这些标记的点都不是起点, 起点是其他点到不了的点。
  2. bfs,从起点广搜,最后一个便是距离起点最远的点了
#include <iostream>
#include <queue>
#include <vector>
using namespace std;
vector<int> arr[100005];
int book[100005];
int main(void){
    int n, m, k, a;
    cin >> n;
    for(int i = 1; i <= n; i ++){
        cin >> m;
        for(int j = 0; j < m; j ++){
            cin >> a;
            book[a] = 1;
            arr[i].push_back(a);
        }
    }
    for(int i = 1; i <= n; i ++){
        if(book[i] == 0){
            k = i;
            break;
        }
    }
   // cout << k << endl;
    queue<int> qu;
    qu.push(k);
    int ans = 0;
    while(!qu.empty()){
        ans = qu.front();
        for(int i = 0; i < arr[ans].size(); i ++){
            qu.push(arr[ans][i]);
        }
        qu.pop();
    }
    cout << ans << endl;
    return 0;
}

正整数A+B

在这里插入图片描述
自己当时写的代码只拿了11分,百度搜的代码中忽视的细节

  1. 数字范围问题,超过[1, 1000]要输出 ?

  2. 空格问题,B是空格输出?,A是空格记为0。

  3. 切字串substr
    s1 = substr(0, a) 0为起始下标,a为从起始下标开始的字符个数。

  4. 将字符串转为数字
    n1 = atoi(s1, c_str())

思路
将输入的一行作为一个字符串s,第一个子串为s1,对应数字记为n1(若不是整数或超出范围记为-1);第二个为s2,对应数字记为n2(与n1同理)。第一个空格下标为a,第二个空格下标为b。
首先找空格的下标,若有多个空格,则第一个空格为分割点,故遍历;若存在超过一个空格,标记n2 = -1,若只存在一个空格,则b = s.length();

#include <algorithm>
#include <iostream>
#include <string>
#include <cstring>
using namespace std;
int main(void){
    string s, s1, s2;
    int n1 = 0, n2 = 0, i, k = 0, a, b;
    getline(cin, s);
    for(int i = 0; i < s.length(); i ++){
        if(s[i] == ' '){
            b = i;
            k ++;
        }
        if(k >= 2){
            n2 = -1;
            break;
        }
        a = b;
    }
    if(k == 1) b = s.length();
    for(int i = 0; i < a; i ++){
        if(s[i] < '0' || s[i] > '9'){
            n1 = -1;
            break;
        }
    }
    for(int i = a + 1; i < b; i ++){
        if(s[i] < '0' || s[i] > '9'){
            n2 = -1;
            break;
        }
    }
    if(n1 != -1 && n2 != -1){
        s1 = s.substr(0, a);
        s2 = s.substr(a + 1, b - a -1);
        n1 = atoi(s1.c_str());
        n2 = atoi(s2.c_str());
        if(n1 >= 1 && n1 <= 1000 && n2 <= 1000 && n2 >= 1){
            printf("%d + %d = %d", n1, n2, n1 + n2);
        }
        else if(n1 >= 1 && n1 <= 1000 &&(n2 < 1 || n2 > 1000)){
            printf("%d + ? = ?", n1);
        }
        else if(n2 >= 1 && n2 <= 1000 &&(n1 < 1 || n1 > 1000)){
            printf("? + %d = ?", n2);
        }
        else printf("? + ? = ?");
    }
    else if(n1 == -1 && n2 != -1){
        s2 = s.substr(a + 1, b - a - 1);
        n2 = atoi(s2.c_str());
        if(n2 >= 1 && n2 <= 1000) printf("? + %d = ?", n2);
        else cout << "? + ? = ?";
    }
    else if(n1 != -1 && n2 == -1){
        s1 = s.substr(0, a);
        n1 = atoi(s1.c_str());
        if(n1 >= 1 && n1 <= 1000) printf("%d + ? = ?", n1);
        else cout <<"? + ? = ?";
    }
    else printf("? + ? = ?");
    return 0;
}

红色警报(并查集)

在这里插入图片描述

做题感悟

  1. 去掉一个点后,我们需要多次建图,这次不妨把建图的代码设置成一个函数。
  2. 一个vis数组建立的很有必要。。
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;

struct node{
    int w, v;
}link[5010];
int n, m, k, last, now;
int vis[505], p[505];
int findp(int x){
    return x == p[x] ? x : p[x] = findp(p[x]);
}
void make_merge(){
    for(int i = 0; i < n; i ++){
        p[i] = i;
    }
    for(int i = 0; i < m; i ++){
        if(vis[link[i].w] && vis[link[i].v]){
            int px = findp(link[i].w), py = findp(link[i].v);
            if(px != py){
                p[py] = px;
            }
        }
    }
}
int cntall(){
    int cnt = 0;
    for(int i = 0; i < n; i ++){
        if(vis[i] && findp(i) == i) cnt ++;
    }
    return cnt;
}
int main(void){
    memset(vis, 1, sizeof(vis));
    cin >> n >> m;
    for(int i = 0; i < m; i ++){
        cin >> link[i].w >> link[i].v;
    }
    make_merge();
    last = now = cntall();
    cin >> k;
    for(int i = 0; i < k; i ++){
        int num;
        cin >> num;
        vis[num] = 0;
        make_merge();
        now = cntall();
        if(now > last) printf("Red Alert: City %d is lost!\n", num);
        else printf("City %d is lost.\n", num);
        last = now;
    }
    now = 0;
    for(int i = 0; i < n; i ++){
        if(vis[i] == 0){
            now ++;
        }
    }
    if(now == n) printf("Game Over.\n");
    return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Xuhx&

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

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

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

打赏作者

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

抵扣说明:

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

余额充值