PAT第五章专题复习
-
数学题
-
A 1049 :统计从1-N中1的个数
-
思路:
①逐位进行考虑。从低位开始,如果当前位now = 0的话,就只需要考虑左边部分的个数。表达式为ans += left * a;
②如果now = 1的话,左边部分计算同理;now位有1个,再加上右边部分的数值。可以得到表达式为ans += left * a + 1 + right
③如果now >= 2的话,没有任何限制,可以得到表达式ans += (left + 1) * a;
-
代码实现
#include<bits/stdc++.h> using namespace std; int main(){ int n; cin >> n; int left, right, now; int a = 1; //10的多少次方 int ans = 0; //记录1的个数 while(n/a != 0){//总共有多少位 left = n / (a * 10);//当前位左边部分的数 right = n % a;//当前位右边部分的数 now = n / a % 10; //当前位上的数 //分三种情况 if(now == 0)ans += left * a; else if(now == 1)ans += left * a + right + 1; else ans += (left + 1) * a; a *= 10; } printf("%d\n", ans); return 0; }
-
-
-
分数运算
-
需要注意答案为0时候的输出。容易犯下0/1类似的错误。
-
A 1088 计算分数的加减乘除运算
-
思路:
①难点在于如何精简写代码。要熟练运用三目运算符。
②调用的func函数中,首先判断,分子分母是否为0,如果分母为0,输出inf;如果分子为0,输出0;满足任意两者都直接return,不用再进行后续操作。
③接着,判断分子与分母是否异号,注意判断的时候不能用m*n<0这样直白来判断,会导致数据过大溢出,符号发生改变。如果为异号,就利用三目运算符输出"(-",否则输出一个空字符串。
④然后求真分数整数部分值,输出。接着判断是否还存在分数部分,如果不存在,且分子分母异号,输出“)”后return返回。如果存在,再接着求解最大公因子,约分输出。
-
代码实现
#include<bits/stdc++.h> using namespace std; long long a, b, c, d; long long gcd(long long t1, long long t2){ if(t2 == 0)return t1; else return gcd(t2, t1 % t2); } //化简并打印函数 void func(long long m, long long n){ if(m * n == 0){ printf("%s", n == 0? "Inf":"0"); return; } //注意以下不能写成m*n<0,会溢出然后变成正数 bool flag = ((m < 0 && n > 0) || (m > 0 && n < 0)); m = abs(m), n = abs(n); long long x = m / n; printf("%s", flag ? "(-" : ""); if(x != 0)printf("%lld", x); if(m % n == 0){ if(flag)printf(")"); return; } if(x != 0)printf(" "); m = m - x * n; long long t = gcd(m, n); m = m / t, n = n / t; printf("%lld/%lld%s", m, n, flag ? ")" : ""); } int main(){ scanf("%lld/%lld %lld/%lld", &a, &b, &c, &d); //加法 func(a, b);printf(" + ");func(c, d); printf(" = ");func(a * d + b * c, b * d);printf("\n"); //减法 func(a, b);printf(" - ");func(c, d); printf(" = ");func(a * d - b * c, b * d);printf("\n"); //乘法 func(a, b);printf(" * ");func(c, d); printf(" = ");func(a * c, b * d);printf("\n"); //除法 func(a, b);printf(" / ");func(c, d); printf(" = ");func(a*d, b * c); return 0; }
-
-
-
素数
-
A 1015 :一个十进制数和它的某一特定进制数反转后转换为的十进制数,两个数是否都是素数。
-
本题有两个坑,一个是题意,不是直接判断d进制数是否为素数,而是仍然要将反转的d进制数再转换为十进制数,然后判断是否为素数。 第二个就是0和1不是素数。求素数问题时,都要注意这一点
-
代码实现
#include<bits/stdc++.h> using namespace std; int a[1000006]; bool judge(long long n){ //注意0和1不是素数,需要写在判断函数里 if(n <= 1)return false; long long sqr = (long long)sqrt(n * 1.0); for(long long i = 2; i <= sqr; i++){ if(n % i == 0){ return false; } } return true; } long long change(int b[], int n, int d){ int index = 0; long long num1 = 0; do{ b[index++] = n % d; n /= d; }while(n != 0) for(int i = 0; i < index; i++){ num1 = num1 * d + b[i]; } return num1; } int main(){ int n, d; while(1){ cin >> n; if(n < 0)break; cin >> d; if(judge(n)){ memset(a, 0, sizeof(a)); long long ans = change(a, n, d); if(judge(ans)){ printf("Yes\n"); }else printf("No\n"); }else printf("No\n"); } return 0; }
-
-
-
质因数
-
A 1096:寻找最大长度的连续质因数序列,如果最大长度相同,输出第一个数字最小的序列
-
思路:
①首先说明一下自己一开始思考的时候的思维漏洞,就是只用for循环遍历了一次,导致漏了很多答案,其实应该用双重for循环来做。
②正确思路:外层for循环从2遍历到sqrt(n) + 1,内层for循环j从i开始,到maxn,寻找最大连续质因数序列。然后跳出内层for循环,判断此次长度是否是最大长度。
-
代码实现
#include<bits/stdc++.h> using namespace std; long long num, temp; int main(){ cin >> num; int first = 0, len = 0, maxn = sqrt(num) + 1; for(int i = 2; i <= maxn; i++){ int j; temp = 1; //通过不断相乘并且是否能够被num整除来寻找最大连续质因数 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){//说明num是一个质数 cout << 1 << endl << num; }else{//说明num不是一个质数 cout << len << endl; for(int i = 0; i < len; i++){ cout << first + i; if(i != len - 1)cout << '*'; } } return 0; }
-
-
-
大数运算
-
A 1024:大数相加并判断是否是回文。
-
思路:
①难点在于将大数相加的过程写清楚,因为是while循环需要进行多次相加,所以最好使用模板代码,比较清晰。自己在写的过程中,没有使用模板代码,导致书写错误。
②熟悉大数运算的操作过程,此代码还需要更加熟悉。
-
代码实现
#include<bits/stdc++.h> using namespace std; struct bign{ int d[1000]; int len; bign(){ memset(d, 0, sizeof(d)); len = 0; } }; bign change(char str[]){ bign a; a.len = strlen(str); for(int i = 0; i < a.len; i++){ a.d[i] = str[a.len - 1 - i] - '0'; } return a; } bign add(bign a, bign b){ bign c; int carry = 0; for(int i = 0; i < a.len || i < b.len; i++){ int temp = a.d[i] + b.d[i] + carry; c.d[c.len++] = temp % 10; carry = temp / 10; } if(carry != 0){ c.d[c.len++] = carry; } return c; } bool judge(bign a){//判断是否是回文 for(int i = 0; i <= a.len / 2; i++){ if(a.d[i] != a.d[a.len-1-i]){ return false; } } return true; } void print(bign a){ for(int i = a.len - 1; i >= 0; i--){ printf("%d", a.d[i]); } printf("\n"); } int main(){ char str[100]; int t, k = 0; cin >> str >> t; bign a = change(str);//大数使用结构体存储,不容易出错 while(k < t && judge(a) == false){ bign b = a; //如果是结构体类型大数,就可以直接赋值 reverse(b.d, b.d + b.len); a = add(a, b); k++; } print(a); printf("%d\n", k); return 0; }
-
-