2021算法笔记Codeup、pat刷题记录
目录
《算法笔记》5.1小节——数学问题->简单数学
Codeup
守形数
#include<cstdio>
int main() {
int num;
while (scanf("%d", &num) != EOF) {
int s = num * num;
bool flag = true;
while (num > 0) {
if (s % 10 != num % 10) {
flag = false;
break;
}
num /= 10;
s /= 10;
}
if (flag == true) printf("Yes!\n");
else printf("No!\n");
}
return 0;
}
反序数
#include<cstdio>
bool is_revnum(int a) {//判断是不是反序数
int temp = 9 * a, b = 0;
for (int i = 0;i < 4;++i) {
b = b * 10 + a % 10;
a /= 10;
}
if (b == temp) return true;
return false;
}
int main() {
int n = 1000;
while (n < 10000) {
if (is_revnum(n)) printf("%d\n", n);
++n;
}
return 0;
}
百鸡问题
能暴力破解为什么要动脑
#include<cstdio>
int main() {
int n;
while (scanf("%d", &n) != EOF) {
for (int i = 0;i <= n / 5;++i) {
for (int j = 0;j <= n / 3;++j) {
for (int k = 0;k <= n * 3;++k) {
if (5 * i + 3 * j + k / 3.0 > 1.0 * n) break;
if (i + j + k == 100) printf("x=%d,y=%d,z=%d\n", i, j, k);
}
}
}
}
return 0;
}
abc
#include<cstdio>
int main() {
// abc+bcc=532
for (int i = 1;i < 10;++i) {
for (int j = 1;j < 10;++j) {
for (int k = 1;k < 10;++k) {
if (100 * i + 10 * j + k + 100 * j + 10 * k + k == 532) printf("%d %d %d\n", i, j, k);
}
}
}
return 0;
}
众数
#include<cstdio>
int main() {
int a;
while (scanf("%d", &a) != EOF) {
int hashTable[15] = { 0 };
++hashTable[a];
for (int i = 0;i < 19;++i) {
scanf("%d", &a);
++hashTable[a];
}
int men = 0, t = 0;
for (int i = 1;i <= 10;++i) {
if (hashTable[i] > t) {
men = i;
t = hashTable[i];
}
}
printf("%d\n", men);
}
return 0;
}
计算两个矩阵的乘积
#include<cstdio>
int main() {
int a[2][3], b[3][2];
while (scanf("%d", &a[0][0]) != EOF) {
int res[2][2] = { 0 };
for (int i = 0;i < 2;++i) {
for (int j = 0;j < 3;++j) {
if (i == 0 && j == 0) continue;
scanf("%d", &a[i][j]);
}
}
for (int i = 0;i < 3;++i) {
for (int j = 0;j < 2;++j) {
scanf("%d", &b[i][j]);
}
}
for (int i = 0;i < 2;++i) {
for (int k = 0;k < 2;++k) {
for (int j = 0;j < 3;++j) {
res[i][k] += a[i][j] * b[j][k];
}
if (k != 0) printf(" ");
printf("%d", res[i][k]);
}
printf("\n");
}
}
return 0;
}
加法等式
同abc
整数和
#include<cstdio>
int main() {
int n;
while (scanf("%d", &n) != EOF) {
for (int i = 0;i < n;++i) {
int m, flag = 1;
scanf("%d", &m);
if (m < 0) {
m = -m;
flag = -1;//通过flag记录最后输出值的正负,将正负数统一处理
}
int m2 = m * 2, sum = 0;
while (m <= m2) {
sum += m;
++m;
}
printf("%d\n", sum * flag);
}
}
return 0;
}
反序相等
同反序数,但是一直运行错误?
多项式的值
#include<cstdio>
int main() {
int m;
scanf("%d", &m);
while (m--) {
int n, a[15], x;
scanf("%d", &n);
for (int i = 0;i < n + 1;++i) {
scanf("%d", &a[i]);
}
scanf("%d", &x);
int sum = 0;
for (int i = n;i >= 0;--i) {
sum = sum * x + a[i];
}
printf("%d\n", sum);
}
return 0;
}
迭代求立方根
#include<cstdio>
int main() {
int x, n;
while (scanf("%d %d", &x, &n) != EOF) {
double y = x;
for (int i = 0;i < n;++i) {
y = y * 2 / 3 + x / (3 * y * y);
}
printf("%.6f\n", y);
}
return 0;
}
与7无关的数
#include<cstdio>
const int maxn = 110;
bool about7(int n) {//判断数n是否关于7
if (n % 7 == 0) return true;
while (n > 0) {
if (n % 10 == 7) return true;
n /= 10;
}
return false;
}
int main() {
int n, s[maxn], cnt = 0;
for (int i = 1;i <= 100;++i) if (!about7(i)) s[cnt++] = i;//将100内所有不关于7的数字存储在s数组中
while (scanf("%d", &n) != EOF) {
int sum = 0;
for (int i = 0;i < cnt && s[i] <= n;++i) {//遍历数组,加上小于n的数字的平方和
sum += s[i] * s[i];
}
printf("%d\n", sum);
}
return 0;
}
鸡兔同笼
#include<cstdio>
int main() {
int n;
scanf("%d", &n);
while (n--) {
int a, min, max;
scanf("%d", &a);
if (a % 2) {
printf("0 0\n");
continue;
}
max = a / 2;
if (a % 4 == 2) min = a / 4 + 1;
else min = a / 4;
printf("%d %d\n", min, max);
}
return 0;
}
配套实战指南
PAT B1003 我要通过!
最开始没太看懂题,后面看懂了没想出来方法,看了晴神笔记之后了解方法后写出的代码有一个点没过,于是copy了晴神的
#include<cstdio>
#include<cstring>
int main() {
int n;
scanf("%d", &n);
while (n--) {
char str[110];
scanf("%s", str);
int len = strlen(str);
int num_p = 0, num_t = 0, other = 0;
int loc_p = -1, loc_t = -1;
for (int i = 0;i < len;++i) {
if (str[i] == 'P') {
num_p++;
loc_p = i;
}
else if (str[i] == 'T') {
++num_t;
loc_t = i;
}
else if (str[i] != 'A') other++;
}
if ((num_p != 1) || (num_t != 1) || other != 0 || (loc_t - loc_p <= 1)) {
printf("NO\n");
continue;
}
int x = loc_p, y = loc_t - loc_p - 1, z = len - loc_t - 1;
if (z - x * (y - 1) == x) {
printf("YES\n");
}
else {
printf("NO\n");
}
}
return 0;
}
PAT A1069 The Black Hole of Numbers/B1019 数字黑洞
#include<cstdio>
#include<algorithm>
using namespace std;
bool cmp(int a, int b) {
return a > b;
}
void to_array(int a[], int num) {
for (int i = 0;i < 4;++i) {
a[i] = num % 10;
num /= 10;
}
}
void to_num(int a[], int& num) {
num = 0;
for (int i = 0;i < 4;++i) num = num * 10 + a[i];
}
int main() {
int num;
scanf("%d", &num);
while (num != 0) {
int Max, Min, a[4];
to_array(a, num);
sort(a, a + 4);
to_num(a, Min);
sort(a, a + 4, cmp);
to_num(a, Max);
num = Max - Min;
printf("%04d - %04d = %04d\n", Max, Min, num);
if (num == 6174) break;
}
return 0;
}
PAT A1104 Sum of Number Segments
很迷的一道题
#include<cstdio>
int main() {
int n;
scanf("%d", &n);
long double a, sum = 0;
for (int i = 0;i < n;++i) {
scanf("%Lf", &a);
sum += a * (i + 1) * (n - i);//sum += (i + 1) * (n - i) * a;不知为何写成这样是错的
}
printf("%.2Lf", sum);
return 0;
}
PAT A1008 Elevator
#include<cstdio>
int main() {
int n, f, ans = 0, now = 0;
scanf("%d", &n);
for (int i = 1;i <= n;++i) {
scanf("%d", &f);
int move = f - now;
now = f;
bool up = true;
if (move < 0) {
up = false;
move = -move;
}
if (up) ans += move * 6 + 5;
else ans += move * 4 + 5;
}
printf("%d", ans);
return 0;
}
PAT A1049 Counting Ones
能暴力求解,为什么…然后就果不其然的超时了,测了下最大数暴力求解要算100多秒,然后就学习了晴神笔记的方法。
#include<cstdio>
int main() {
int n, ans = 0, a = 1;
scanf("%d", &n);
int num = n;
for (int i = 0;n > 0;++i, n /= 10, a *= 10) {
int digit = n % 10, left = n / 10, right = num - n * a;
if (digit == 0) ans += left * a;
else if (digit == 1) ans += left * a + right + 1;
else ans += (left + 1) * a;
}
printf("%d", ans);
return 0;
}
《算法笔记》5.2小节——数学问题->最大公约数与最小公倍数
Codeup
Least Common Multiple
#include<cstdio>
int gcd(int a, int b) {
return !b ? a : gcd(b, a % b);
}
int main() {
int m;
while (scanf("%d", &m) != EOF) {
while (m--) {
int a, b, n, res;
scanf("%d %d", &n, &a);
for (int i = 0;i < n - 1;++i) {
scanf("%d", &b);
a = a / gcd(a, b) * b;
}
printf("%d\n", a);
}
}
return 0;
}
配套实战指南
1008 数组元素循环右移问题
这样写是移动最少的写法,考试时时长限制不严格的情况下不可能会这么想这么写的。
#include<cstdio>
int gcd(int a, int b) {
return !b ? a : gcd(b, a % b);
}
int main() {
int a[110];
int n, m;
scanf("%d %d", &n, &m);
for (int i = 0;i < n;++i) scanf("%d", &a[i]);
m = m % n;
if (m != 0) {
int d = gcd(n, m);
for (int i = n - m;i < n - m + d;++i) {//从n-m枚举到n-m+d-1位结束
int next, temp = a[i], pos = i;
do {
next = (pos - m + n) % n;
if (next != i) a[pos] = a[next];
else a[pos] = temp;
pos = next;
} while (pos != i);
}
}
for (int i = 0;i < n;++i) {
printf("%d", a[i]);
if (i < n - 1) printf(" ");
}
return 0;
}
《算法笔记》5.3小节——数学问题->分数的四则运算
Codeup
分数矩阵
找规律题,前面写了个时间超限的,发现各数字的个数规律即可写出。
#include<cstdio>
int main() {
int n;
while (scanf("%d", &n) != EOF, n) {
double res = n * 1.0;
for (int i = 1;i < n;++i) {
res += (1.0 / (i + 1)) * 2 * (n - i);
}
printf("%.2f\n", res);
}
return 0;
}
配套实战指南
编译器得用clang++
#include<cstdio>
#include<cmath>
struct rationalNum {//分数结构体
long long up, down;
}sum, temp;
long long gcd(long long a, long long b) {//最大公约数
return !b ? a : gcd(b, a % b);
}
void reduction(rationalNum& a) {//化简
if (a.up == 0) a.down = 1;
else {
long long d = gcd(abs(a.up), abs(a.down));
a.up /= d;
a.down /= d;
}
}
void add(rationalNum& a, rationalNum b) {//分数相加
a.up = a.up * b.down + b.up * a.down;
a.down = a.down * b.down;
reduction(a);
}
void printResult(rationalNum a) {//分数输出
if (a.down == 1) printf("%lld", a.up);
else if (abs(a.up) > a.down) {
printf("%lld %lld/%lld", a.up / a.down, abs(a.up) % a.down, a.down);
}
else {
printf("%lld/%lld", a.up, a.down);
}
printf("\n");
}
int main() {
int n;
scanf("%d", &n);
sum.down = 1;
sum.up = 0;//初始化sum
for (int i = 0;i < n;++i) {
scanf("%lld/%lld", &temp.up, &temp.down);
add(sum, temp);
}
printResult(sum);
return 0;
}
PAT A1088 Rational Arithmetic/B1034 有理数四则运算
代码挺长,但不难
#include<cstdio>
#include<algorithm>
typedef long long ll;
using namespace std;
struct Fraction {
ll up, down;
}a, b, res;
ll gcd(ll a, ll b) {
return !b ? a : gcd(b, a % b);
}
void reduction(Fraction& a) {
if (a.down < 0) {
a.up = -a.up;
a.down = -a.down;
}
if (a.up == 0) a.down = 1;
else {
int d = gcd(abs(a.up), abs(a.down));
a.up /= d;
a.down /= d;
}
}
Fraction add(Fraction a, Fraction b) {
Fraction temp;
temp.up = a.up * b.down + b.up * a.down;
temp.down = a.down * b.down;
reduction(temp);
return temp;
}
Fraction minu(Fraction a, Fraction b) {
Fraction temp;
temp.up = a.up * b.down - b.up * a.down;
temp.down = a.down * b.down;
reduction(temp);
return temp;
}
Fraction multi(Fraction a, Fraction b) {
Fraction temp;
temp.up = a.up * b.up;
temp.down = a.down * b.down;
reduction(temp);
return temp;
}
Fraction divide(Fraction a, Fraction b) {
Fraction temp;
temp.up = a.up * b.down;
temp.down = a.down * b.up;
reduction(temp);
return temp;
}
void printRes(Fraction a) {
reduction(a);
if (a.up < 0) printf("(");
if (a.down == 1) printf("%lld", a.up);
else if (abs(a.up) > a.down) printf("%lld %lld/%lld", a.up / a.down, abs(a.up) % a.down, a.down);
else printf("%lld/%lld", a.up, a.down);
if (a.up < 0) printf(")");
}
int main() {
scanf("%lld/%lld %lld/%lld", &a.up, &a.down, &b.up, &b.down);
//加法
printRes(a);
printf(" + ");
printRes(b);
printf(" = ");
printRes(add(a, b));
printf("\n");
//减法
printRes(a);
printf(" - ");
printRes(b);
printf(" = ");
printRes(minu(a, b));
printf("\n");
//乘法
printRes(a);
printf(" * ");
printRes(b);
printf(" = ");
printRes(multi(a, b));
printf("\n");
//除法
printRes(a);
printf(" / ");
printRes(b);
printf(" = ");
if (b.up == 0) printf("Inf");
else printRes(divide(a, b));
printf("\n");
return 0;
}
《算法笔记》5.4小节——数学问题->素数
Codeup
素数
#include<cstdio>
const int maxn = 10010;
bool p[maxn] = { false };
int prime[maxn], cnt = 0;
void Find_Prime() {
for (int i = 2;i < maxn;++i) {
if (!p[i]) {
prime[cnt++] = i;
for (int j = i + i;j < maxn;j += i) {
p[j] = true;
}
}
}
}
int main() {
Find_Prime();
int n;
while (scanf("%d", &n) != EOF) {
int i = 0, cnt = 0;
while (prime[i] < n) {
if (prime[i] % 10 == 1) {
printf("%d ", prime[i]);
++cnt;
}
++i;
}
if (!cnt) printf("-1");
printf("\n");
}
return 0;
}
Prime Number
#include<cstdio>
const int maxn = 1000010;
bool p[maxn] = { false };
int prime[maxn], cnt = 1;
void Find_Prime() {
for (int i = 2;i < maxn;++i) {
if (!p[i]) {
prime[cnt++] = i;
for (int j = i + i;j < maxn;j += i) {
p[j] = true;
}
}
}
}
int main() {
Find_Prime();
int k;
while (scanf("%d", &k) != EOF) {
printf("%d\n", prime[k]);
}
return 0;
}
Goldbach’s Conjecture
#include<cstdio>
const int maxn = 500000;
bool p[maxn] = { false };
int prime[maxn], cnt = 0;
void Find_prime() {
for (int i = 2;i < maxn;++i) {
if (!p[i]) {
prime[cnt++] = i;
for (int j = i + i;j < maxn;j += i) {
p[j] = true;
}
}
}
}
void get_ans(int n) {
int left = 0, right = cnt - 1;
int count = 0;
while (left < right) {
while ((prime[left] + prime[right]) > n) --right;
if (prime[left] + prime[right] == n) count++;
++left;
}
printf("%d\n", count);
}
int main() {
Find_prime();
int n;
while (scanf("%d", &n) != EOF, n) {
get_ans(n);
}
return 0;
}
配套实战指南
PAT B1007 素数对猜想
#include<cstdio>
const int maxn = 100010;
bool p[maxn] = { false };
int prime[maxn], cnt = 1;
int d[maxn] = { 0 }, dc = 1;
void Find_Prime() {
for (int i = 2;i < maxn;++i) {
if (!p[i]) {
prime[cnt] = i;
if (cnt > 1) d[dc++] = prime[cnt] - prime[cnt - 1];
++cnt;
for (int j = i + i;j < maxn;j += i) {
p[j] = true;
}
}
}
}
int main() {
Find_Prime();
int n;
scanf("%d", &n);
int cnt = 0;
for (int i = 1;prime[i] <= n;++i) {
if (d[i - 1] == 2) ++cnt;
}
printf("%d", cnt);
return 0;
}
PAT B1013 数素数
#include<cstdio>
const int maxn = 1000001;
bool p[maxn] = { false };
int prime[maxn] = { 0 }, cnt = 0;
void Find_Prime(int n) {
for (int i = 2;cnt <= n;++i) {
if (!p[i]) {
prime[cnt++] = i;
for (int j = i + i;j < maxn;j += i) {
p[j] = true;
}
}
}
}
int main() {
int m, n, count = 0;
scanf("%d %d", &m, &n);
Find_Prime(n);
for (int i = m - 1;i < n;++i) {
count++;
printf("%d", prime[i]);
if (count % 10 && i != n - 1) printf(" ");
else printf("\n");
}
return 0;
}
PAT A1015 Reversible Primes
#include<cstdio>
const int maxn = 1000010;
bool p[maxn] = { false,true };//保证1不能为YES
void Find_Prime() {
for (int i = 2;i < maxn;++i) {
if (!p[i]) {
for (int j = i + i;j < maxn;j += i) {
p[j] = true;
}
}
}
}
int main() {
Find_Prime();
int n;
while (scanf("%d", &n), n > 0) {
int d, num[40] = { 0 }, cnt = 0;
scanf("%d", &d);
if (p[n]) {
printf("No\n");
continue;
}
do {
num[cnt++] = n % d;
n /= d;
} while (n > 0);
for (int i = 0;i < cnt;++i) n = n * d + num[i];
if (p[n]) printf("No\n");
else printf("Yes\n");
}
return 0;
}
PAT A1078 Hashing
最开始错误最后一个点因为不认识这个词组的意思。
Quadratic probing(with positive increments only)——指的是二次方探查法,且只往正向解决冲突。当step自增到Tsize的时候如果还没找到可用位置则表示这个元素无法被插入。
#include<cstdio>
const int maxn = 10010;
bool p[maxn] = { false,true };
void Find_Prime() {
for (int i = 2;i < maxn;++i) {
if (!p[i]) {
for (int j = i + i;j < maxn;j += i) {
p[j] = true;
}
}
}
}
int main() {
Find_Prime();
int Msize, n, a[maxn], Tsize;
bool hashTable[maxn] = { false };
scanf("%d %d", &Msize, &n);
for (int i = 0;i < n;++i) scanf("%d", &a[i]);
for (int i = Msize;i < maxn;++i) {//从Msize往后找Tsize,当p[i]==false的时候即是第一个素数。
if (!p[i]) {
Tsize = i;
break;
}
}
for (int i = 0;i < n;++i) {
if (i > 0) printf(" ");
int k = a[i] % Tsize;
if (!hashTable[k]) {
printf("%d", k);
hashTable[k] = true;
}
else {
int step;
for (step = 1;step < Tsize;++step) {
int m = (k + step * step) % Tsize;
if (!hashTable[m]) {
hashTable[m] = true;
printf("%d", m);
break;
}
}
if (step >= Tsize) printf("-");
}
}
return 0;
}
《算法笔记》5.5小节——数学问题->质因子分解
Codeup
完数
别看代码这么长,实际上的时间复杂度并不高,计算因子和使用了书上的公式,先找出所有质因子,再通过公式找出完数并输出。题目中说了数字不大,因此也可以采用枚举的方法找出一个数的所有因子并加和然后比较大小。
#include<cstdio>
#include<cmath>
const int maxn = 100010;
bool p[maxn] = { false,true };
int prime[maxn], cnt = 0;
void Find_Prime() {//找素数
for (int i = 2;i < maxn;++i) {
if (!p[i]) {
prime[cnt++] = i;
for (int j = i + i;j < maxn;j += i) {
p[j] = true;
}
}
}
}
struct fractor {//质因数
int x, cnt;
}fac[10];
int main() {
Find_Prime();
int n, num;
while (scanf("%d", &n) != EOF) {
int sqr = sqrt(1.0 * n), count = 0;
for (int i = 2;i <= n;++i) {
int m = i;
num = 0;
for (int j = 0;j < cnt && prime[j] <= sqr;++j) {
if (m % prime[j] == 0) {
fac[num].x = prime[j];
fac[num].cnt = 0;
while (m % prime[j] == 0) {
++fac[num].cnt;
m /= prime[j];
}
++num;
}
if (m == 1) break;
}
if (m != 1) {
fac[num].x = m;
fac[num++].cnt = 1;
}
int sum = 1;
for (int j = 0;j < num;++j) {
int temp = 0;
for (int k = 0;k <= fac[j].cnt;++k) {
temp += pow(fac[j].x, k);//公式
}
sum *= temp;
}
sum -= i;
if (sum == i) {
if (count != 0) printf(" ");
printf("%d", sum);
++count;
}
if (i == n) printf("\n");
}
}
return 0;
}
质因数的个数
算个数的话无需记录质因子的值,因此只需int一个count,每有一个质因子时++即可。
#include<cstdio>
#include<cmath>
const int maxn = 100010;
bool p[maxn] = { false,true };
int prime[maxn], cnt = 0;
void Find_Prime() {
for (int i = 2;i < maxn;++i) {
if (!p[i]) {
prime[cnt++] = i;
for (int j = i + i;j < maxn;j += i) {
p[j] = true;
}
}
}
}
int main() {
Find_Prime();
int n;
while (scanf("%d", &n) != EOF) {
int count = 0;
for (int i = 0;i < cnt;++i) {
while (n % prime[i] == 0) {
++count;
n /= prime[i];
}
if (n == 1) break;
}
if (n != 1) {
++count;
}
printf("%d\n", count);
}
return 0;
}
约数的个数
套公式计算
#include<cstdio>
#include<cmath>
const int maxn = 100010;
bool p[maxn] = { false,true };
int prime[maxn], cnt = 0;
void Find_Prime() {
for (int i = 2;i < maxn;++i) {
if (!p[i]) {
prime[cnt++] = i;
for (int j = i + i;j < maxn;j += i) {
p[j] = true;
}
}
}
}
struct factor {
int x, cnt;
}fac[10];
int main() {
Find_Prime();
int m;
while (scanf("%d", &m), m) {
while (m--) {
int num = 0, n;
scanf("%d", &n);
if (n == 1) {
printf("1\n");
continue;
}
for (int i = 0;i < cnt;++i) {
if (n % prime[i] == 0) {
fac[num].x = i;
fac[num].cnt = 0;
while (n % prime[i] == 0) {
++fac[num].cnt;
n /= prime[i];
}
++num;
}
if (n == 1) break;
}
if (n != 1) {
fac[num].x = n;
fac[num++].cnt = 1;
}
int ans = 1;
for (int i = 0;i < num;++i) {
ans *= (fac[i].cnt + 1);//公式计算
}
printf("%d\n", ans);
}
}
return 0;
}
完数与盈数
直接拿着完数代码改得
#include<cstdio>
#include<cmath>
const int maxn = 100010;
bool p[maxn] = { false,true };
int prime[maxn], cnt = 0;
void Find_Prime() {//找素数
for (int i = 2;i < maxn;++i) {
if (!p[i]) {
prime[cnt++] = i;
for (int j = i + i;j < maxn;j += i) {
p[j] = true;
}
}
}
}
struct fractor {//质因数
int x, cnt;
}fac[10];
int main() {
Find_Prime();
int n = 60, num, E[60], ce = 0, G[60], cg = 0;
int sqr = sqrt(1.0 * n), count = 0;
for (int i = 2;i <= n;++i) {
int m = i;
num = 0;
for (int j = 0;j < cnt && prime[j] <= sqr;++j) {
if (m % prime[j] == 0) {
fac[num].x = prime[j];
fac[num].cnt = 0;
while (m % prime[j] == 0) {
++fac[num].cnt;
m /= prime[j];
}
++num;
}
if (m == 1) break;
}
if (m != 1) {
fac[num].x = m;
fac[num++].cnt = 1;
}
int sum = 1;
for (int j = 0;j < num;++j) {
int temp = 0;
for (int k = 0;k <= fac[j].cnt;++k) {
temp += pow(fac[j].x, k);//公式
}
sum *= temp;
}
sum -= i;
if (sum == i) {
E[ce++] = i;
}
else if (sum > i) {
G[cg++] = i;
}
}
printf("E:");
for (int i = 0;i < ce;++i) printf(" %d", E[i]);
printf("\nG:");
for (int i = 0;i < cg;++i) printf(" %d", G[i]);
printf("\n");
return 0;
}
配套实战指南
PAT A1096 Consecutive Factors
#include<cstdio>
#include<cmath>
int main() {
int n;
scanf("%d", &n);
int sqr = sqrt(n * 1.0), anslen = 0, s = 0;
for (int i = 2;i <= sqr;++i) {
int num = n, lenth = 0;
if (num % i == 0) {
for (int k = 0;num % (i + k) == 0;++k) {
++lenth;
num /= (i + k);
}
if (lenth > anslen) {
s = i;
anslen = lenth;
}
}
}
if (anslen == 0) {//最大长度为0时,说明根号n范围内无解(包括小于4的数和质数)
printf("1\n%d", n); //此时输出n本身
}
else {
printf("%d\n", anslen);
for (int i = s;i < s + anslen;++i) {
if (i != s) printf("*");
printf("%d", i);
}
}
return 0;
}
PAT A1059 Prime Factors
不要忘记特判n=1的情况
#include<cstdio>
#include<cmath>
const int maxn = 100010;
bool p[maxn] = { false, true };
int prime[maxn], cnt = 0;
void Find_Prime() {
for (int i = 2;i < maxn;++i) {
if (!p[i]) {
prime[cnt++] = i;
for (int j = i + i;j < maxn;j += i) {
p[j] = true;
}
}
}
}
struct factor {
int x, cnt;
}fac[10];
int main() {
Find_Prime();
int n, num = 0;
scanf("%d", &n);
if (n == 1) printf("1=1");
else {
int sqr = (int)sqrt(1.0 * n);
printf("%d=", n);
for (int i = 0;i < cnt, prime[i] <= sqr;++i) {
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) break;
}
if (n != 1) {
fac[num].x = n;
fac[num++].cnt = 1;
}
for (int i = 0;i < num;++i) {
if (i > 0) printf("*");
printf("%d", fac[i].x);
if (fac[i].cnt > 1) printf("^%d", fac[i].cnt);
}
}
return 0;
}
《算法笔记》5.6小节——数学问题->大整数运算
Codeup
a+b
#include<cstdio>
#include<cstring>
const int maxn = 1010;
struct bign {
int d[maxn];
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 - i - 1] - '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) {
c.d[c.len++] = carry;
}
return c;
}
void print(bign a) {
for (int i = a.len - 1;i >= 0;--i) {
printf("%d", a.d[i]);
}
printf("\n");
}
int main() {
char str1[maxn], str2[maxn];
while (scanf("%s %s", &str1, &str2) != EOF) {
bign a, b;
a = change(str1);
b = change(str2);
bign c = add(a, b);
print(c);
}
return 0;
}
N的阶乘
#include<cstdio>
#include<cstring>
const int maxn = 100010;
struct bign {
int d[maxn];
int len;
bign() {
memset(d, 0, sizeof(d));
len = 0;
}
};
bign multi(bign a, int b) {
bign c;
int carry = 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) {
c.d[c.len++] = carry % 10;
carry /= 10;
}
return c;
}
void print(bign a) {
for (int i = a.len - 1;i >= 0;--i) {
printf("%d", a.d[i]);
}
printf("\n");
}
int main() {
int n;
while (scanf("%d", &n) != EOF) {
if (n == 0) printf("1\n");
else {
bign a;
a.d[0] = 1;
a.len = 1;
for (int i = 1;i <= n;++i) a = multi(a, i);
print(a);
}
}
return 0;
}
浮点数加法
写了好久,不知道该怎么写,感觉自己的思路并不是最好的,提交了三次,犯了些不该犯的错误。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 110;
struct bign {
int d[maxn], f[maxn];
int dlen, flen;
bign() {
memset(d, 0, sizeof(d));
memset(f, 0, sizeof(f));
dlen = flen = 0;
}
};
bign change(char str[]) {
int len = strlen(str);
int d;
for (d = 0;d < len;++d) if (str[d] == '.') break;
bign a;
a.dlen = d;
a.flen = len - d - 1;
int i;
for (i = 0;i < a.dlen && i < a.flen;++i) {
a.d[i] = str[a.dlen - i - 1] - '0';
a.f[i] = str[len - i - 1] - '0';
}
while (i < a.dlen) {
a.d[i] = str[a.dlen - i - 1] - '0';
++i;
}
while (i < a.flen) {
a.f[i] = str[len - i - 1] - '0';
++i;
}
return a;
}
bign add(bign a, bign b) {
bign c;
int carry = 0, i = 0;
if (b.flen > a.flen) {//保证后面只要用一个while来计算
swap(a.flen, b.flen);
swap(b.f, a.f);
}
while (b.flen + i != a.flen) c.f[c.flen++] = a.f[i++];
for (int j = 0;i + j < a.flen;++j) {
int temp = a.f[j + i] + b.f[j] + carry;
c.f[c.flen++] = temp % 10;
carry = temp / 10;
}
int k;//去除末尾0
for (k = 0;k < c.flen;++k) if (c.f[k] != 0) break;
for (int l = 0;l + k < c.flen;++l) c.f[l] = c.f[l + k];
c.flen -= k;
for (int i = 0;i < a.dlen || i < b.dlen;++i) {
int temp = a.d[i] + b.d[i] + carry;
c.d[c.dlen++] = temp % 10;
carry = temp / 10;
}
if (carry) {
c.d[c.dlen++] = carry % 10;
}
return c;
}
void print(bign a) {
for (int i = a.dlen - 1;i >= 0;--i) {
printf("%d", a.d[i]);
}
printf(".");
for (int i = a.flen - 1;i >= 0;--i) {
printf("%d", a.f[i]);
}
printf("\n");
}
int main() {
int n;
while (scanf("%d", &n) != EOF) {
char str[maxn];
while (n--) {
scanf("%s", str);
bign a = change(str);
scanf("%s", str);
bign b = change(str);
bign c = add(a, b);
print(c);
}
}
return 0;
}
进制转换
这题想了很久,原因在于对进制转换的不熟练,对于任意的m进制到n进制使用辗转相除法不太会,学习了。
#include<cstdio>
#include<cstring>
const int maxn = 1010;
struct bign {
int d[maxn];
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) {
if (str[a.len - i - 1] >= '0' && str[a.len - i - 1] <= '9') a.d[i] = str[a.len - i - 1] - '0';
else a.d[i] = str[a.len - i - 1] - 'A' + 10;
}
return a;
}
int main() {
int m, n;
while (scanf("%d %d", &m, &n) != EOF) {
char str[maxn], ans[maxn];
int cnt = 0;
scanf("%s", str);
bign a = change(str);
while (a.len > 0) {//辗转相除法
int r = 0;
for (int i = a.len - 1;i >= 0;--i) {
r = a.d[i] + r * m;
a.d[i] = r / n;
r = r % n;
}
while (a.d[a.len - 1] == 0) --a.len;
if (r >= 0 && r <= 9) ans[cnt++] = r + '0';
else ans[cnt++] = r - 10 + 'a';
}
for (int i = cnt - 1;i >= 0;--i) {
printf("%c", ans[i]);
}
printf("\n");
}
return 0;
}
大整数排序
答案错误检查之后发现竟然是有一个--i
写成了++i
晕死
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 1010;
struct bign {
int d[maxn];
int len;
bign() {
memset(d, 0, sizeof(d));
len = 0;
}
}b[110];
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;
}
bool cmp(bign a, bign b) {
if (a.len != b.len) return a.len < b.len;
for (int i = a.len - 1;i >= 0;--i) {
if (a.d[i] != b.d[i]) return a.d[i] < b.d[i];
}
}
void print(bign a) {
for (int i = a.len - 1;i >= 0;--i) printf("%d", a.d[i]);
printf("\n");
}
int main() {
int n;
while (scanf("%d", &n) != EOF) {
char str[maxn];
for (int i = 0;i < n;++i) {
scanf("%s", str);
b[i] = change(str);
}
sort(b, b + n, cmp);
for (int i = 0;i < n;++i) print(b[i]);
}
return 0;
}
10进制 VS 2进制
总是会犯一些小错误,导致查错很久(无语),这次是a.len后面忘记写-1,不可粗心。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 100010;
struct bign {
int d[maxn];
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 - i - 1] - '0';
}
return a;
}
bign conversion(bign a, int n, int m) {//n进制到m进制
bign b;
while (a.len > 0) {//辗转相除法
int r = 0;
for (int i = a.len - 1;i >= 0;--i) {
r = a.d[i] + r * n;
a.d[i] = r / m;
r = r % m;
}
while (a.d[a.len - 1] == 0) --a.len;
b.d[b.len++] = r;
}
return b;
}
bign reverse(bign a) {
for (int i = 0;i < a.len / 2;++i) swap(a.d[i], a.d[a.len - i - 1]);
while (a.d[a.len - 1] == 0) --a.len;
return a;
}
void print(bign a) {
for (int i = a.len - 1;i >= 0;--i) {
printf("%d", a.d[i]);
}
printf("\n");
}
int main() {
char str[1010];
while (scanf("%s", str) != EOF) {
bign a = change(str);
a = conversion(a, 10, 2);
a = reverse(a);
a = conversion(a, 2, 10);
print(a);
}
return 0;
}
配套实战指南
PAT B1017 A除以B
本题要注意结果为0时,得输出0;
#include<cstdio>
#include<cstring>
const int maxn = 1010;
struct bign {
int d[maxn];
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 - i - 1] - '0';
}
return a;
}
bign divide(bign a, int n, int& r) {
r = 0;
for (int i = a.len - 1;i >= 0;--i) {
r = a.d[i] + r * 10;
a.d[i] = r / n;
r = r % n;
}
while (a.d[a.len - 1] == 0 && a.len - 1) --a.len;//注意不要减去最后一位
return a;
}
void print(bign a) {
for (int i = a.len - 1;i >= 0;--i) {
printf("%d", a.d[i]);
}
printf(" ");
}
int main() {
char str[maxn];
int n, r;
scanf("%s %d", str, &n);
bign a = change(str);
a = divide(a, n, r);
print(a);
printf("%d\n", r);
return 0;
}
PAT B1023 Have Fun with Numbers
#include<cstdio>
#include<cstring>
const int maxn = 25;
int hashTable[10] = { 0 };//记录10以内数的个数
struct bign {
int d[maxn];
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 - i - 1] - '0';
++hashTable[a.d[i]];//对应数的个数++
}
return a;
}
bign multi(bign a, int n) {
int carry = 0;
bign c;
for (int i = 0;i < a.len;++i) {
int temp = a.d[i] * n + carry;
c.d[c.len++] = temp % 10;
carry = temp / 10;
--hashTable[c.d[i]];//减去对应数
}
while (carry) {
c.d[c.len++] = carry % 10;
carry /= 10;
}
return c;
}
void print(bign a) {
for (int i = a.len - 1;i >= 0;--i) {
printf("%d", a.d[i]);
}
printf("\n");
}
int main() {
char str[maxn];
scanf("%s", str);
bign a = change(str);
int i;
a = multi(a, 2);
for (i = 0;i < 10;++i) {
if (hashTable[i] != 0) {
printf("No\n");
break;
}
}
if (i == 10) printf("Yes\n");
print(a);
return 0;
}
PAT A1024 Palindromic Number
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 110;
struct bign {
int d[maxn];
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 - i - 1] - '0';
}
return a;
}
bign reverse(bign a) {
for (int i = 0;i < a.len / 2;++i) {
swap(a.d[i], a.d[a.len - i - 1]);
}
return a;
}
bign add(bign a, bign b) {
bign c;
int carry = 0;
for (int i = 0;i < a.len;++i) {
int temp = a.d[i] + b.d[i] + carry;
c.d[c.len++] = temp % 10;
carry = temp / 10;
}
if (carry) 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 - i - 1]) 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[maxn];
int n;
scanf("%s %d", str, &n);
int i;
bign a = change(str);
for (i = 0;i < n;++i) {
if (judge(a)) break;
a = add(a, reverse(a));
}
print(a);
printf("%d", i);
return 0;
}
《算法笔记》5.7小节——数学问题->扩展欧几里德算法
《算法笔记》5.8小节——数学问题->组合数
PAT貌似不考,暂时略过。