算法笔记.胡凡 第五章 数学问题

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 = p1​k1​×p2​k2​×⋯×pm​km​.

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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值