PAT甲级题分类汇编——计算

本文为PAT甲级分类汇编系列文章。html

 

计算类,指以数学运算为主或为背景的题。ios

题号 标题 分数 大意
1058 A+B in Hogwarts 20 特殊进制加法
1059 Prime Factors 25 分解素因数
1060 Are They Equal 25 必定精度下两数是否相等
1065 A+B and C (64bit) 20 大数加法与比较
1069 The Black Hole of Numbers 20 黑洞数
1073 Scientific Notation 20 科学计数法还原
1081 Rational Sum 20 有理数加法
1088 Rational Arithmetic 20 有理数运算
1096 Consecutive Factors 20 最长连续因数
1100 Mars Numbers 20 进制转换

这类题,广泛分数低,大可能是20分。20分题放到乙级也没啥问题,好比106九、1081等。然而,即便是20分题,也可能要卡好久。函数

我挑了1059106510881096共4道来作。spa

 

1059:code

题目要求输出一个数的素因数分解。这么简单的题就很少讲了吧,直接上代码:htm

 1 #include <iostream>
 2 #include <map>
 3 #include <cmath>
 4 
 5 bool isprime(int n)
 6 {
 7     int end = std::sqrt(n) + 1;
 8     for (int i = 2; i != end; ++i)
 9         if (n % i == 0)
10             return false;
11     return true;
12 }
13 
14 int main(int argc, char const *argv[])
15 {
16     long n;
17     std::cin >> n;
18     std::cout << n << '=';
19     if (n == 1)
20     {
21         std::cout << '1';
22         return 0;
23     }
24     std::map<int, int> factors;
25     int prime = 2;
26     while (n > 1)
27     {
28         if (isprime(prime) && n % prime == 0)
29         {
30             ++factors[prime];
31             n /= prime;
32         }
33         else
34             ++prime;
35     }
36     int count = 0;
37     for (const auto& pair : factors)
38     {
39         if (count++)
40             std::cout << '*';
41         std::cout << pair.first;
42         if (pair.second > 1)
43             std::cout << '^' << pair.second;
44     }
45     return 0;
46 }

其实用 std::vector 也是能够的,但我懒。blog

须要注意的是 n==1 的检查,不过这个很容易发现。ci

 

1065:get

要求判断两个64位整数相加是否大于另外一个数。注意两个64位整数相加之后若是还保存在64位整数中是可能溢出的,而且test case里面必定会有这种状况。数学

因此要用更大的整数来作计算。然而C++标准库中并无提供128位整数。这时,伟大的g++出现了,它提供了 __int128_t :

 1 #include <iostream>
 2 
 3 int main(int argc, char const *argv[])
 4 {
 5     int t;
 6     std::cin >> t;
 7     std::cout << std::boolalpha;
 8 
 9     for (int i = 1; i <= t; ++i)
10     {
11         __int128_t a, b, c;
12         int64_t ta, tb, tc;
13         std::cin >> ta >> tb >> tc;
14         a = ta; b = tb; c = tc;
15         std::cout << "Case #" << i << ": " << (a + b > c) << std::endl;
16     }
17 
18     return 0;
19 }

因而这道题就被秒了。

C++标准库对整数类型的支持不太好,大整数的类只能本身写。至因而以二进制存储仍是以十进制存储,那要看应用场景了。

 

1088:

在一个case上卡了很久,最后发现题目里有一句要用 long int ,WCNM。

难度没什么的,主要是对分子和分母有0或1的特殊状况的处理。

优雅的我写了一份很优雅的实现,又是template又是运算符重载的:

  1 #include <iostream>
  2 #include <exception>
  3 
  4 template <typename T>
  5 class Rational
  6 {
  7 public:
  8     Rational() = default;
  9     Rational(T _num, T _den)
 10         : numerator(_num), denominator(_den)
 11     {
 12         reduce();
 13     }
 14     Rational(const Rational&) = default;
 15     Rational& operator=(const Rational&) = default;
 16 
 17     Rational operator+(const Rational& _rhs) const noexcept
 18     {
 19         return Rational(numerator * _rhs.denominator + _rhs.numerator * denominator,
 20             denominator * _rhs.denominator);
 21     }
 22     Rational operator-(const Rational& _rhs) const noexcept
 23     {
 24         return Rational(numerator * _rhs.denominator - _rhs.numerator * denominator,
 25             denominator * _rhs.denominator);
 26     }
 27     Rational operator*(const Rational& _rhs) const noexcept
 28     {
 29         return Rational(numerator * _rhs.numerator,
 30             denominator * _rhs.denominator);
 31     }
 32     Rational operator/(const Rational& _rhs) const
 33     {
 34         if (_rhs.numerator == 0)
 35             throw std::exception();
 36         return Rational(numerator * _rhs.denominator,
 37             denominator * _rhs.numerator);
 38     }
 39 
 40     template <typename U>
 41     friend std::istream& operator>>(std::istream&, Rational<U>&);
 42     template <typename U>
 43     friend std::ostream& operator<<(std::ostream&, const Rational<U>&);
 44 private:
 45     static T gcd(T _lhs, T _rhs)
 46     {
 47         if (_lhs < 0)
 48             _lhs = -_lhs;
 49         if (_lhs < _rhs)
 50             return gcd(_rhs, _lhs);
 51         if (_rhs == 0)
 52             return _lhs ? _lhs : 1;
 53         return gcd(_rhs, _lhs % _rhs);
 54     }
 55 
 56     void reduce()
 57     {
 58         if (denominator < 0)
 59         {
 60             numerator = -numerator;
 61             denominator = -denominator;
 62         }
 63         auto factor = gcd(numerator, denominator);
 64         numerator /= factor;
 65         denominator /= factor;
 66     }
 67 
 68     T numerator;
 69     T denominator;
 70 };
 71 
 72 template <typename T>
 73 std::istream& operator>>(std::istream& _is, Rational<T>& _r)
 74 {
 75     T n, d;
 76     std::cin >> n;
 77     std::cin.get();
 78     std::cin >> d;
 79     _r = Rational<T>(n, d);
 80     return _is;
 81 }
 82 
 83 template <typename T>
 84 std::ostream& operator<<(std::ostream& _os, const Rational<T>& _r)
 85 {
 86     auto r = _r;
 87     bool neg = false;
 88     if (r.numerator < 0)
 89     {
 90         neg = true;
 91         r.numerator = -r.numerator;
 92         _os << "(-";
 93     }
 94     if (r.denominator == 1)
 95         _os << r.numerator;
 96     else
 97     {
 98         if (r.numerator >= r.denominator)
 99         {
100             _os << (r.numerator / r.denominator) << ' ';
101             r.numerator %= r.denominator;
102         }
103         _os << r.numerator << '/' << r.denominator;
104     }
105     if (neg)
106         _os << ')';
107     return _os;
108 }
109 
110 int main(int argc, char const *argv[])
111 {
112     Rational<long long> lhs, rhs;
113     std::cin >> lhs >> rhs;
114     std::cout << lhs << " + " << rhs << " = " << (lhs + rhs) << std::endl;
115     std::cout << lhs << " - " << rhs << " = " << (lhs - rhs) << std::endl;
116     std::cout << lhs << " * " << rhs << " = " << (lhs * rhs) << std::endl;
117     std::cout << lhs << " / " << rhs << " = ";
118     try
119     {
120         std::cout << (lhs / rhs) << std::endl;
121     }
122     catch(const std::exception& e)
123     {
124         std::cout << "Inf" << std::endl;
125     }
126     return 0;
127 }

优雅个屁,考试要来不及的。

顺便讲讲写自定义类(特指有成员方法的类而非简单的结构体)和模板的技巧。

构造函数最好给一个默认的,Rule of Three/Five规定的方法最好显式 =default 写出来。

参数尽可能用引用,看状况要不要加 const ,大多都是要加的。相应地,成员方法能用 const 修饰的必定要加上去。

对于模板类的友元函数,模板类中还要再套模板,并且要用不同的类型名称。

以上规则若是不遵照,极可能会编译错误,并且错误信息看起来比较累。

 

1096:

要求输出给定整数的的分解中能够出现的最长连续因数。乍一看有一点难,但稍微想想就会发现,这串因数不会太长,由于阶乘是很大的。因此能够一个一个试这串因数中的最小数,连续不少个因数只有没几种状况须要试,到连续两个的状况,也是O(sqrt(n))时间复杂度能搞定的。至于单个因数则须要单独讨论一下,由于试到根号n就能够了,而若是不中止的话会超时。

 1 #include <iostream>
 2 #include <utility>
 3 #include <cmath>
 4 
 5 int main(int argc, char const *argv[])
 6 {
 7     int n;
 8     std::cin >> n;
 9 
10     try
11     {
12         for (int count = 11; count > 1; --count)
13         {
14             for (int min = 2; ; ++min)
15             {
16                 long product = 1;
17                 for (int factor = min; factor != min + count; ++factor)
18                     product *= factor;
19                 if (product > n)
20                     break;
21                 if (n % product == 0)
22                     throw std::pair<int, int>(count, min);
23             }
24         }
25         int end = std::sqrt(n) + 1;
26         for (int factor = 2; factor != end; ++factor)
27             if (n % factor == 0)
28                 throw std::pair<int, int>(1, factor);
29         throw std::pair<int, int>(1, n);
30     }
31     catch(const std::pair<int, int>& pair)
32     {
33         std::cout << pair.first << std::endl;
34         for (int i = pair.second; i != pair.second + pair.first - 1; ++i)
35             std::cout << i << '*';
36         std::cout << pair.second + pair.first - 1 << std::endl;
37     }
38 
39     return 0;
40 }

长度的初始值是11,是由于2*3*...*13是大于2^31的,而2*3*...*12是小于2^31的,所以长度不会超过11。

 

总之,计算类题目没有难度,可是要避坑。坑依然是边界条件,包括最小的数(0、一、2等)与很大的数(int放不下的)。

相关文章
相关标签/搜索