5.1 简单数学
【PAT A1069】
For any 4-digit integer except the ones with all the digits being the same, if we sort the digits in non-increasing order first, and then in non-decreasing order, a new number can be obtained by taking the second number from the first one. Repeat in this manner we will soon end up at the number 6174
-- the black hole of 4-digit numbers. This number is named Kaprekar Constant.
For example, start from 6767
, we'll get:
7766 - 6677 = 1089
9810 - 0189 = 9621
9621 - 1269 = 8352
8532 - 2358 = 6174
7641 - 1467 = 6174
... ...
Given any 4-digit number, you are supposed to illustrate the way it gets into the black hole.
Input Specification:
Each input file contains one test case which gives a positive integer N in the range (0,104).
Output Specification:
If all the 4 digits of N are the same, print in one line the equation N - N = 0000
. Else print each step of calculation in a line until 6174
comes out as the difference. All the numbers must be printed as 4-digit numbers.
Sample Input 1:
6767
结尾无空行
Sample Output 1:
7766 - 6677 = 1089
9810 - 0189 = 9621
9621 - 1269 = 8352
8532 - 2358 = 6174
结尾无空行
Sample Input 2:
2222
结尾无空行
Sample Output 2:
2222 - 2222 = 0000
结尾无空行
#include<iostream>
#include<algorithm>
using namespace std;
bool cmp(char a, char b){return a > b;}
int main(){
string s;
cin >> s;
s.insert(0,4-s.length(),'0');
do{
string max = s, min = s;
sort(max.begin(), max.end(), cmp);
sort(min.begin(),min.end());
int result = stoi(max) - stoi(min);
s = to_string(result);
s.insert(0,4-s.length(),'0');
cout<< max <<" - "<< min <<" = "<< s << endl;
} while (s != "6174" && s != "0000");
return 0;
}
5.2 最大公约数与最小公倍数
最大公约数:欧几里得算法,即辗转相除法。
gcd(a, b) = gcd(b, a % b)
int gcd(int a, int b) {
if (b == 0) return a;
else return gcd(b, a % b);
}
int gcd(int x, int y) {
int z = y;
while (x % y != 0) {
z = x % y;
x = y;
y = z;
}
return z;
}
最小公倍数 = a * b / 最大公约数
lcm(a, b) = a * b / gcd(a, b)
5.3 分数的四则运算
5.3.1 分数的表示和化简
1.分数的表示
struct Fraction { //分数
int up, down;//分子、分母
}
三项规则:
①down为非负数。如果分数为负,那么令分子up为负即可。
②如果分数恰好为0,那么让分子为0,分母为1。
③分子和分母没有除了1以外的公约数。
2.分数的化简
①如果分母down为负数,那么令分子up和分母down都变为相反数
②如果分子up为0,那么令分母down为1。
③约分:求出分子绝对值和分母绝对值的最大公约数d,然后令分子分母同时除以d。
5.3.2 分数的四则运算
1.分数的加法
2.分数的减法
3. 分数的乘法
4. 分数的除法
5.3.3 分数的输出
①输出分数之前,需要对其进行化简。
②如果分数r分母为1,说明分数为整数,一般直接输出分子即可。
③如果分数r分子up的绝对值大于分母down,说明是假分数,此时应该按照带分数的形式输出,即整数部分为r.up / r.down,分子部分为abs(r.up) / r.down,分母为r.down。
④以上均不满足时说明分数r是真分数,按照原样输出即可。
为了防止分数的乘法或者除法超出int型表示范围,因此分子和分母应该使用long long型来存储。
5.4 素数
5.4.1 素数的判断
#include<math.h>
bool isPrime(int n) {
if (n <= 1) return false;
int sqr = (int) sqrt(1.0 * n);
for (int i = 2; i <= sqr; i ++) {
if (n % i == 0) return false;
}
return true;
}
5.4.2 素数表的获取
const int maxn = 100;//表长
int prime[maxn], pNum = 0;
bool p[maxn] = {0}; //p[i]为true说明i是素数
void Find_Prime() {
for (int i = 1; i < maxn; i++) {
if(isPrime(i) == true) {
prime[pNum++] = i;
p[i] = true;
}
}
}
5.4.3 素数筛法
依次类推。
const int maxn = 100;
int prime[maxn], pNum = 0;
bool p[maxn] = {0};
void Find_Prime() {
for (int i = 2; i < maxn; i++) {//不能写成<=
if (p[i] == false) {//i是素数
prime[pNum++] = i;
for (int j = i + 1; j < maxn; j +=i) {//筛去所有i的倍数
p[j] = true;
}
}
}
}
【PAT B1013】数素数
令 Pi 表示第 i 个素数。现任给两个正整数 M≤N≤104,请输出 PM 到 PN 的所有素数。
输入格式:
输入在一行中给出 M 和 N,其间以空格分隔。
输出格式:
输出从 PM 到 PN 的所有素数,每 10 个数字占 1 行,其间以空格分隔,但行末不得有多余空格。
输入样例:
5 27
结尾无空行
输出样例:
11 13 17 19 23 29 31 37 41 43
47 53 59 61 67 71 73 79 83 89
97 101 103
结尾无空行
#include <iostream>
#include <vector>
using namespace std;
bool isprime(int a) {
for (int i = 2; i * i <= a; i++)
if(a % i == 0) return false;
return true;
}
int main() {
int M, N, num = 2, cnt = 0;
cin >> M >> N;
vector<int> v;
while (cnt < N) {
if (isprime(num)) {
cnt++;
if (cnt >= M) v.push_back(num);
}
num++;
}
cnt = 0;
for (int i = 0; i < v.size(); i++) {
cnt++;
if (cnt % 10 != 1) printf(" ");
printf("%d", v[i]);
if (cnt % 10 == 0) printf("\n");
}
return 0;
5.5 质因子分解
质因子分解是指将一个正整数n写成一个或者多个质数的乘积的形式。
定义一个结构体factor,用来存放质因子及其个数,如下所示:
struct factor {
int x, cnt;
} fac[10];
//对于180来说,fac数组如下所示:180 = 2 * 2 * 3 * 3 * 5
fac[0].x = 2
fac[0].cnt = 2
fac[1].x = 3
fac[1].cnt = 2
fac[2].x = 5
fac[2].cnt = 1
对于一个正整数n来说,如果它存在[2,n]范围内的质因子,要么这些质因子全部小于sqrt(n),要么只存在一个大于sqrt(n)的质因子,其余质因子都小于等于sqrt(n)。
思路:
①枚举1~sqrt(n)内的所有质因子p,判断p是否是n的因子。如果是,则给fac数组增加质因子p,并初始化其个数为0。然后,只要p还是n的因子,就让n不断除以p,每次操作令p的个数加1,直到p不再是n的因子为止。如果p不是n的质因子,直接跳过。
②如果在上面的步骤结束后,n仍然大于1,说明n有且仅有一个大于sqrt(n)的质因子,这时只需要把这个质因子加入到fac数组,并令其个数为1。
if (n % prime[i] == 0) {
fac[num].x = prime[i];
fac[num].cnt = 0;
while (n % prime[i] == 0) {
fac[num].cnt++;
n /= prime[i];
}
num ++;
}
if(n != 1) {
fac[num].x = n;
fac[num].cnt = 1;
}
【PAT A1059】
Given any positive integer N, you are supposed to find all of its prime factors, and write them in the format N = p1k1×p2k2×⋯×pmkm.
Input Specification:
Each input file contains one test case which gives a positive integer N in the range of long int.
Output Specification:
Factor N in the format N =
p1^
k1*
p2^
k2*
…*
pm^
km, where pi's are prime factors of N in increasing order, and the exponent ki is the number of pi -- hence when there is only one pi, ki is 1 and must NOT be printed out.
Sample Input:
97532468
结尾无空行
Sample Output:
97532468=2^2*11*17*101*1291
结尾无空行
//例题PAT-A-1059-Prime-Factors
#include <cstdio>
#include <cmath>
#include <iostream>
using namespace std;
const int maxn = 100010;
bool is_prime(int n)//判断n是否为素数
{
if(n==1) return false;
int sqr = (int)sqrt(1.0*n);
for(int i=2;i<=sqr;i++)
{
if(n%i==0)
return false;
}
return true;
}
int prime[maxn],pNum = 0;
void Find_Prime()//求素数表
{
for(int i=1;i<maxn;i++)
{
if(is_prime(i) == true)
prime[pNum++] = i;
}
}
struct factor
{
int x,cnt;//x为质因数,cnt为其个数
}fac[10];
int main()
{
Find_Prime();
int n,num=0;//num为n的不同的质因子个数
scanf("%d",&n);
// cin>>n;
if(n == 1)
printf("1=1");
// cout<<"1=1";
else
{
printf("%d=",n);
// cout<<n<<"=";
int sqr = (int)sqrt(1.0*n);//n的根号
//枚举根号n以内的质因子
for(int i=0;i<pNum && prime[i] <= sqr;i++)
{
if(n % prime[i] == 0)//如果prime[i]是n的质因子
{
fac[num].x = prime[i];//记录该因子
fac[num].cnt = 0;
while(n % prime[i] == 0)//计算出质因子的个数
{
fac[num].cnt++;
n /= prime[i];
}
num++;//不同质因子个数加一
}
if(n == 1) break;//及时退出循环节省时间
}
if(n != 1)//如果无法被根号n以内的质因子除尽
{
fac[num].x = n;//那么一定有 一个 大于根号n的质因子
fac[num++].cnt = 1;
}
//按格式输出结果
for(int i=0;i<num;i++)
{
if(i>0) cout<<"*";
cout<<fac[i].x;
if(fac[i].cnt > 1)
{
cout<<"^"<<fac[i].cnt;
}
}
}
return 0;
}
5.6 大整数运算
对于大整数来说,一般把大整数的每一位存在数组里面,整数的高位存放在数组的高位,整数的低位存放在数组的低位。
struct bign {
int d[10000];
int len;
bign() {
memset(d, 0, sizeof(d));
len = 0;
}
};
在输入大整数时,一般先用字符串读入,然后把字符串另存至bign结构体中。需要注意的是逆向读入。
bign change(char str[]) {
bign a;
a.len = strlen(str);
for (int i = 0; i < a.len; i ++) {
a.d[i] = str[a.len - i - 1] - '0';
}
return a;
}
5.6.1 高精度加法
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;
}
5.6.2 高精度减法
bign sub(bign a, bign b) {
bign c;
for (int i = 0; i < a.len || i < b.len; i++) {
if (a.d[i] < b.d[i]) {
a.d[i+1]--;
a.d[i]+= 10;
}
c.d[c.len++] = a.d[i] - b.d[i];
}
while(c.len - 1 >= 1 && c.d[c.len-1] == 0) {
c.len -- ;//去除高位0,同时至少保留一位最低位
}
return c;
}
如果减数小于被减数,需要交换两个变量,然后输出负号,再使用sub函数。
5.6.3 高精度与低精度乘法
bign multi(bign a, int b) {
bign c;
int caryy = 0;
for (int i = 0; i < a.len; i++) {
int temp = a.d[i] * b + carry;
c.d[c.len++] = temp % 10;
carry = temp / 10;
}
while (carry != 0) {
c.d[c.len++] = carry % 10;
carry /= 10;
}
return c;
}
5.6.4 高精度与低精度除法
bign divide(bign a, int b, int& r) {
bign c;
c.len = a.len;
for (int i = a.len - 1; i >= 0; i--) {
r = r * 10 + a.d[i];
if (r < b) c.d[i] = 0;
else {
c.d[i] = r / b;
r = r % b;
}
}
while (c.len - 1 > 1 && c.d[c.len-1] == 0) {
c.len --;
}
return c;
}