mituh's notes


  • 首页

  • 归档

1074 宇宙无敌加法器(20) - PAT乙级

发表于 2018-08-26

1074 宇宙无敌加法器(20)

地球人习惯使用十进制数,并且默认一个数字的每一位都是十进制的。而在 PAT 星人开挂的世界里,每个数字的每一位都是不同进制的,这种神奇的数字称为“PAT数”。每个 PAT 星人都必须熟记各位数字的进制表,例如“……0527”就表示最低位是 7 进制数、第 2 位是 2 进制数、第 3 位是 5 进制数、第 4 位是 10 进制数,等等。每一位的进制 d 或者是 0(表示十进制)、或者是 [2,9] 区间内的整数。理论上这个进制表应该包含无穷多位数字,但从实际应用出发,PAT 星人通常只需要记住前 20 位就够用了,以后各位默认为 10 进制。

在这样的数字系统中,即使是简单的加法运算也变得不简单。例如对应进制表“0527”,该如何计算“6203 + 415”呢?我们得首先计算最低位:3 + 5 = 8;因为最低位是 7 进制的,所以我们得到 1 和 1 个进位。第 2 位是:0 + 1 + 1(进位)= 2;因为此位是 2 进制的,所以我们得到 0 和 1 个进位。第 3 位是:2 + 4 + 1(进位)= 7;因为此位是 5 进制的,所以我们得到 2 和 1 个进位。第 4 位是:6 + 1(进位)= 7;因为此位是 10 进制的,所以我们就得到 7。最后我们得到:6203 + 415 = 7201。

输入格式:

输入首先在第一行给出一个 N 位的进制表(0 < N ≤ 20),以回车结束。 随后两行,每行给出一个不超过 N 位的非负的 PAT 数。

输出格式:

在一行中输出两个 PAT 数之和。

输入样例:

30527
06203
415

输出样例:

7201

Solution:

每次循环继承上一次循环的进位, 进行加法运算, 再求余。

利用栈, 先对后出的特性, 对从右向左计算出的答案打印。
要注意的是,

  • 1, 需要把栈中最前的0给去掉
  • 2, 还要debug结果位0的情况, case5
  • 3, 实际上最后一位(最左)仍然需要进位, 需要在循环外进行判断, case1, 3

如下:

// 1, 3wrong
2
5
7
0

// 5, wrong
2
0
0

实际代码如下:

#include <iostream>
#include <string>
#include <stack>
using namespace std;

int main() {

string T, S1, S2; cin >> T >> S1 >> S2;
int n = T.length();
S1.insert(0, n - S1.length(), '0');
S2.insert(0, n - S2.length(), '0');
stack<int> stk; int more = 0;

for (int i = n-1; i >= 0; i--) {
int b = T[i] == '0' ? 10 : T[i] - '0';
int d = S1[i]-'0' + S2[i]-'0' + more;
int digit = (d) ? (d) % b : 0;
more = d / b;
stk.push(digit);
}
if (more) stk.push(more); // case1, 3
int flag = 0, flag_z = 1;
while (!stk.empty()) {
if (!flag) {
if (stk.top() == 0) {
stk.pop();
} else {
flag = 1;
flag_z = 0; // case5, zero
}
} else {
printf("%d", stk.top());
stk.pop();
}
}
if (flag_z) printf("0");
printf("\n");
return 0;
}

1056 组合数的和(15) - PAT乙级

发表于 2018-08-26

1056 组合数的和(15)

tags: [组合, 算法, PAT]
给定 N 个非 0 的个位数字,用其中任意 2 个数字都可以组合成 1 个 2 位的数字。要求所有可能组合出来的 2 位数字的和。例如给定 2、5、8,则可以组合出:25、28、52、58、82、85,它们的和为330。

输入格式:

输入在第一行中给出 N(1 < N < 10),随后一行给出 N 个不同的非 0 个位数字。数字间以空格分隔。

输出格式:

输出所有可能组合出来的2位数字的和。

输入样例:

3
2 8 5

输出样例:

330

Solution:

#include <cstdio>

int a[15];
int main() {
int N; scanf("%d", &N);
int sum = 0;
for (int i = 0; i < N; i++) {scanf("%d", &a[i]);}

for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
if (i == j) continue;
sum += 10*a[i] + a[j];
}
}
printf("%d", sum);
return 0;
}

1015 德才论(25) - PAT乙级

发表于 2018-08-26

1015 德才论(25)

宋代史学家司马光在《资治通鉴》中有一段著名的“德才论”:“是故才德全尽谓之圣人,才德兼亡谓之愚人,德胜才谓之君子,才胜德谓之小人。凡取人之术,苟不得圣人,君子而与之,与其得小人,不若得愚人。”

现给出一批考生的德才分数,请根据司马光的理论给出录取排名。

输入格式:

输入第一行给出 3 个正整数,分别为:N(≤10^5​​),即考生总数;L(≥60),为录取最低分数线,即德分和才分均不低于 L 的考生才有资格被考虑录取;H(<100),为优先录取线——德分和才分均不低于此线的被定义为“才德全尽”,此类考生按德才总分从高到低排序;才分不到但德分到线的一类考生属于“德胜才”,也按总分排序,但排在第一类考生之后;德才分均低于 H,但是德分不低于才分的考生属于“才德兼亡”但尚有“德胜才”者,按总分排序,但排在第二类考生之后;其他达到最低线 L 的考生也按总分排序,但排在第三类考生之后。

随后 N 行,每行给出一位考生的信息,包括:准考证号 德分 才分,其中准考证号为 8 位整数,德才分为区间 [0, 100] 内的整数。数字间以空格分隔。

输出格式:

输出第一行首先给出达到最低分数线的考生人数 M,随后 M 行,每行按照输入格式输出一位考生的信息,考生按输入中说明的规则从高到低排序。当某类考生中有多人总分相同时,按其德分降序排列;若德分也并列,则按准考证号的升序输出。

输入样例:

14 60 80
10000001 64 90
10000002 90 60
10000011 85 80
10000003 85 80
10000004 80 85
10000005 82 77
10000006 83 76
10000007 90 78
10000008 75 79
10000009 59 90
10000010 88 45
10000012 80 100
10000013 90 99
10000014 66 60

输出样例:

12
10000013 90 99
10000012 80 100
10000003 85 80
10000011 85 80
10000004 80 85
10000007 90 78
10000006 83 76
10000005 82 77
10000002 90 60
10000014 66 60
10000008 75 79
10000001 64 90

Solution:

多加一个rank变量排序

#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;

struct Node {
char id[10];
int dei, cai, score, rank;
};
const int MAXN = 100050;
Node nodes[MAXN];

bool cmp(Node n1, Node n2) {
if (n1.rank != n2.rank) return n1.rank < n2.rank;
if (n1.score != n2.score) return n1.score > n2.score;
if (n1.dei != n2.dei) return n1.dei > n2.dei;
return strcmp(n1.id, n2.id) < 0;
}

int main() {
int N, L, H;
scanf("%d %d %d", &N, &L, &H);
int cnt = 0;
for (int i = 0; i < N; i++) {
char id[10]; int dei, cai;
scanf("%s %d %d", id, &dei, &cai);
if (dei >= L && cai >= L) {
int rank;
if (cai >= H && dei >= H) rank = 1;
else if (dei >= H && cai < H) rank = 2;
else if (dei < H && cai < H && dei >= cai) rank = 3;
else rank = 4;
sscanf(id, "%s", nodes[cnt].id); // why?
nodes[cnt].dei = dei; nodes[cnt].cai = cai;
nodes[cnt].score = dei + cai;
nodes[cnt].rank = rank; cnt++;
}
}
sort(nodes, nodes+cnt, cmp);
printf("%d\n", cnt);
for (int i = 0; i < cnt; i++) {
if (i) printf("\n");
printf("%s %d %d", nodes[i].id, nodes[i].dei,
nodes[i].cai);
}
return 0;
}

344. Reverse String - LeetCode

发表于 2018-08-24

344. Reverse String

Write a function that takes a string as input and returns the string reversed.

Example 1:

Input: “hello”
Output: “olleh”

Example 2:

Input: “A man, a plan, a canal: Panama”
Output: “amanaP :lanac a ,nalp a ,nam A”

Solution:

// 创建新串
// Time:O(n), Space:O(n);
class Solution {
public:
string reverseString(string s) {
string str;
for (int i = s.length()-1; i >= 0; i--) {
str += s[i];
}
return str;
}
};
// 折半交换
// Time: O(n), Space: O(1)
class Solution {
public:
string reverseString(string s) {
int n = s.length();
for (int i = 0; i <= floor(n/2)-1; i++) {
char tmp = s[i]; s[i] = s[n-1-i];; s[n-1-i] = tmp;
}
return s;
}
};
// two pointers
// Time: O(n), Space: O(1)
class Solution {
public:
string reverseString(string s) {
int n = s.length();
int i = 0, j = n-1;
while (i < j) {
int tmp = s[i]; s[i] = s[j]; s[j] = tmp;
i++; j--;
}
return s;
}
};

48. Rotate Image - LeetCode

发表于 2018-08-24

48. Rotate Image

You are given an n x n 2D matrix representing an image.

Rotate the image by 90 degrees (clockwise).

Note:

You have to rotate the image in-place, which means you have to modify the input 2D matrix directly. DO NOT allocate another 2D matrix and do the rotation.

Example 1:

Given input matrix = 
[
[1,2,3],
[4,5,6],
[7,8,9]
],

rotate the input matrix in-place such that it becomes:
[
[7,4,1],
[8,5,2],
[9,6,3]
]

Example 2:

Given input matrix =
[
[ 5, 1, 9,11],
[ 2, 4, 8,10],
[13, 3, 6, 7],
[15,14,12,16]
],

rotate the input matrix in-place such that it becomes:
[
[15,13, 2, 5],
[14, 3, 4, 1],
[12, 6, 8, 9],
[16, 7,10,11]
]

Solution:

1 2 3    7 8 9    7 4 1 
4 5 6 -> 4 5 6 -> 8 5 2
7 8 9 1 2 3 9 6 3

先将每一行反转, 然后在沿着对角线反转.

class Solution {
public:
void rotate(vector<vector<int>>& matrix) {
reverse(matrix.begin(), matrix.end());
for (int i = 0; i < matrix.size()-1; i++) {
for (int j = i+1; j < matrix.size(); j++) {
swap(matrix[i][j], matrix[j][i]);
}
}
}
};

1051 复数乘法(15) - PAT乙级

发表于 2018-08-24

1051 复数乘法(15)

复数可以写成 (A+Bi) 的常规形式,其中 A 是实部,B 是虚部,i 是虚数单位,满足 i2=−1;也可以写成极坐标下的指数形式 (R×e(Pi)),其中 R 是复数模,P 是辐角,i 是虚数单位,其等价于三角形式 (R(cos(P)+isin(P))。

现给定两个复数的 R 和 P,要求输出两数乘积的常规形式。

输入格式:

输入在一行中依次给出两个复数的R1, R2, P1, P2数字间以空格分隔。

输出格式:

在一行中按照 A+Bi 的格式输出两数乘积的常规形式,实部和虚部均保留 2 位小数。注意:如果 B 是负数,则应该写成 A-|B|i 的形式。

输入样例:

2.3 3.5 5.2 0.4

输出样例:

-8.68-8.23i

Solution:

需要补充(复习)一下复数的运算法则:

(a+ib) + (c+id) = (a+c)+(b+d)i
(a+ib) - (c+id) = (a-c)+(b-d)i

复数的乘法:
(a+ib) * (c+id) = ac + adi + bci + bdi^2
= ac + (ad+bc)i - bd
= (ac-bd) + (ad+bc)i

这题里面给出的三角形式有问题, 给出的公式少了一个括号, 如果按照 R*cos(P) + i*sin(p)进行转换的话, 是有问题的.

因为正确的公式是 R * ( cos(p) + i*sin(p) ), 带入后可以得到最终的A+Bi

double A = r1 * r2 * cos(p1) * cos(p2) - r1 * r2 * sin(p1) * sin(p2);
double B = r1 * r2 * cos(p1) * sin(p2) + r1 * r2 * sin(p1) * cos(p2);

另外这题要注意的是, 要把-0.00-0.00i ==转换成==> 0.00+0.00i
如果A实际比0小, 但是很接近0, 不处理的话, 会出现-0.00的情况,
同理B是一样的, 但无论是什么情况, B都要带上i

#include <cstdio>
#include <cmath>

int main() {
double r1, p1, r2, p2;
scanf("%lf %lf %lf %lf", &r1, &p1, &r2, &p2);
double A = r1 * r2 * cos(p1) * cos(p2) - r1 * r2 * sin(p1) * sin(p2);
double B = r1 * r2 * cos(p1) * sin(p2) + r1 * r2 * sin(p1) * cos(p2);
// A = -0.0005;
// B = -0.0005;
if (A + 0.005 >= 0 && A < 0) {
printf("0.00");
} else {
printf("%.2lf", A);
}

if (B >= 0) {
printf("+%.2lfi\n", B);
} else if (B + 0.005 >= 0 && B < 0) {
printf("+0.00i\n"); // 我并不知道有这种边界条件, 为什么0的时候还有i日
} else {
printf("%.2lfi\n", B);
}

return 0;
}

1049 数列的片段和(20) - PAT乙级

发表于 2018-08-24

1049 数列的片段和(20)

给定一个正数数列,我们可以从中截取任意的连续的几个数,称为片段。例如,给定数列 { 0.1, 0.2, 0.3, 0.4 },我们有 (0.1) (0.1, 0.2) (0.1, 0.2, 0.3) (0.1, 0.2, 0.3, 0.4) (0.2) (0.2, 0.3) (0.2, 0.3, 0.4) (0.3) (0.3, 0.4) (0.4) 这 10 个片段。

给定正整数数列,求出全部片段包含的所有的数之和。如本例中 10 个片段总和是 0.1 + 0.3 + 0.6 + 1.0 + 0.2 + 0.5 + 0.9 + 0.3 + 0.7 + 0.4 = 5.0。

输入格式:

输入第一行给出一个不超过10^5的正整数 N,表示数列中数的个数,第二行给出 N 个不超过 1.0 的正数,是数列中的数,其间以空格分隔。

输出格式:

在一行中输出该序列所有片段包含的数之和,精确到小数点后 2 位。

输入样例:

4
0.1 0.2 0.3 0.4

输出样例:

5.00

Solution:

3 5 9 8 1

3 5 9 8 1 // n 个 1
35 59 98 81 // n-1 个 2
359 598 981 // n-2 个 3
3598 5981 // ...
35981 // 1 个n

可直接归纳得到每个位置数被算了多少次

3  5     9      8        1
5 4+4 3+3+3 2+2+2+2 1+1+1+1+1

i位置的数, 被计算了(n-i)*(i+1)次

得到代码:

#include <cstdio>

int main() {
int N; scanf("%d", &N);
double sum = 0.0, tmp;
for (int i = 0; i < N; i++) {
scanf("%lf", &tmp);
sum += tmp * (N-i)*(i+1);
}
printf("%.2lf", sum);
return 0;
}

1068 万绿丛中一点红(20) - PAT乙级

发表于 2018-08-24

1068 万绿丛中一点红(20)

对于计算机而言,颜色不过是像素点对应的一个 24 位的数值。现给定一幅分辨率为 M×N 的画,要求你找出万绿丛中的一点红,即有独一无二颜色的那个像素点,并且该点的颜色与其周围 8 个相邻像素的颜色差充分大。

输入格式:

输入第一行给出三个正整数,分别是 M 和 N(≤ 1000),即图像的分辨率;以及 TOL,是所求像素点与相邻点的颜色差阈值,色差超过 TOL 的点才被考虑。随后 N 行,每行给出 M 个像素的颜色值,范围在 [0,2^24​​) 内。所有同行数字间用空格或 TAB 分开。

输出格式:

在一行中按照 (x, y): color 的格式输出所求像素点的位置以及颜色值,其中位置 x 和 y 分别是该像素在图像矩阵中的列、行编号(从 1 开始编号)。如果这样的点不唯一,则输出 Not Unique;如果这样的点不存在,则输出 Not Exist。

输入样例 1:

8 6 200
0 0 0 0 0 0 0 0
65280 65280 65280 16711479 65280 65280 65280 65280
16711479 65280 65280 65280 16711680 65280 65280 65280
65280 65280 65280 65280 65280 65280 165280 165280
65280 65280 16777015 65280 65280 165280 65480 165280
16777215 16777215 16777215 16777215 16777215 16777215 16777215 16777215

输出样例 1:

(5, 3): 16711680

输入样例 2:

4 5 2
0 0 0 0
0 0 3 0
0 0 0 0
0 5 0 0
0 0 0 0

输出样例 2:

Not Unique

输入样例 3:

3 3 5
1 2 3
3 4 5
5 6 7

输出样例 3:

Not Exist

Solution:

这道题本身没什么难度, 特别的是, 由于题目表述含糊, 很多实际的判断条件要根据实际调试得到:

比如以下,
坑点:

  • 1, 充分大不意味着是最大, 只要是满足比TOL就行了。
  • 2, 需要每个相邻位置满足比TOL大, 不是一个, 也不是总和.
  • 3, 当只有一个颜色的时候, 只输出它, 不然case5通不过.
  • 4, 序号是从1开始的, 在最后print时候+1就好了.

我自己发现的一些问题,

  • 1, Hash表来判断是否有颜色重复, 但是有2^24, 表很大。 memset的话超时, 因此不用memset, 让Node的构造函数自己去置cnt为0
  • 2, c++里面不要用move作为变量名去定义, 会冲突.
  • 3, struct后的;不要再忘记了。
#include <cstdio>
#include <cmath>
#include <vector>
#include <cstring>
using namespace std;
struct Node {
int x;
int y;
int color;
int cnt;
}; // bug01

const int MAXN = 16777300; // pow(2, 24) + 50; // bug02
const int MAXM = 1100;
Node dup_color[MAXN];
int a[MAXM][MAXM];

int grid[9][3] = {{-1, -1}, {-1, 0}, {-1, 1}, // bug03, 不能定义成move
{0 , -1}, {0, 1},
{1, -1}, {1 , 0}, {1, 1}};

int main() {
int M, N, TOL;
scanf("%d %d %d", &M, &N, &TOL);
// memset(dup_color, 0, sizeof(dup_color)); // memset导致空间不足case1,2,3..
// memset(a, 0, sizeof(a));
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
int id; scanf("%d", &id);
a[i][j] = id;
if (dup_color[id].cnt == 0) {
dup_color[id].color = id;
dup_color[id].x = i; dup_color[id].y = j;
}
dup_color[id].cnt++;
}
}
if (M == 1 && N == 1) {
printf("(1, 1): %d\n", a[0][0]);
return 0;
}
vector<Node> v; vector<Node> max_v;
for (int i = 0; i < MAXN; i++) {
if (dup_color[i].cnt == 1) {
v.push_back(dup_color[i]);
}
}

int max_d = 0;
for (int iv = 0; iv < v.size(); iv++) {
int i = v[iv].x, j = v[iv].y, color = v[iv].color; // 难道是色彩均超过TOL?
int delta = 0, ok = 1;
for (int k = 0; k < 8; k++) {
int x = i + grid[k][0], y = j + grid[k][1];
if (0 <= x && x < M && 0 <= y && y < N) {
int color_b = a[x][y];
int dd = abs(color_b-color);
if (dd > TOL) { // 单个超过TOL
delta += dd; // bug03:充分大,不是最大
} else {
ok = 0;
}
}
}
if (ok && delta != 0) {
max_v.push_back(v[iv]);
}
}
if (max_v.size() == 1) {
printf("(%d, %d): %d\n", max_v[0].y+1, max_v[0].x+1, max_v[0].color);
} else if (max_v.size() == 0) {
printf("Not Exist\n");
} else {
printf("Not Unique\n");
}
return 0;
}

1065 单身狗(25) - PAT乙级

发表于 2018-08-24

1065 单身狗(25)

“单身狗”是中文对于单身人士的一种爱称。本题请你从上万人的大型派对中找出落单的客人,以便给予特殊关爱。

输入格式:

输入第一行给出一个正整数 N(≤ 50 000),是已知夫妻/伴侣的对数;随后 N 行,每行给出一对夫妻/伴侣——为方便起见,每人对应一个 ID 号,为 5 位数字(从 00000 到 99999),ID 间以空格分隔;之后给出一个正整数 M(≤ 10 000),为参加派对的总人数;随后一行给出这 M 位客人的 ID,以空格分隔。题目保证无人重婚或脚踩两条船。

输出格式:

首先第一行输出落单客人的总人数;随后第二行按 ID 递增顺序列出落单的客人。ID 间用 1 个空格分隔,行的首尾不得有多余空格。

输入样例:

3
11111 22222
33333 44444
55555 66666
7
55555 44444 10000 88888 22222 11111 23333

输出样例:

5
10000 23333 44444 55555 88888

Solution:

建立两张Hash表, 一张情侣id之间的映射, 另外一张是用于判断要查找的id是否已经有它的爱人出现过。

就是说, 查找时, 抛开查找的几个人不说, 判断它是不是有情侣, 然后再看它的情侣是不是出现在这次晚会中了。
先它将id映射到情侣的id, 如果存在它的情侣, 删除它的情侣(自己本身不需要添加); 如果不存在情侣, 或者是情侣没来, 就把自己添加到单身狗表中。

最后剩下的就是单身狗表。

坑点是:
char* 作为key值不行, 不清楚什么原因, 就用string吧。

#include <iostream>
#include <map>
#include <string>
using namespace std;

int main() {
int N; cin >> N;
map<string, string> pairs;
for (int i = 0; i < N; i++) {
string id_a, id_b; cin >> id_a >> id_b; // why? char*不可以
pairs[id_a] = id_b;
pairs[id_b] = id_a;
}

int M; cin >> M;
map<string, int> mp;
for (int i = 0; i < M; i++) {
string id_tmp; cin >> id_tmp;

if (pairs.count(id_tmp)) {
auto it = mp.find(pairs[id_tmp]);
if (it != mp.end()) {
mp.erase(it);
} else {
mp[id_tmp] = 1;
}
} else {
mp[id_tmp] = 1;
}
}

cout << mp.size() << endl;
for (auto it = mp.begin(); it != mp.end(); it++) {
if (it != mp.begin()) cout << " ";
cout << it->first;
}
return 0;
}

1064 朋友数(20) - PAT乙级

发表于 2018-08-24

1064 朋友数(20)

如果两个整数各位数字的和是一样的,则被称为是“朋友数”,而那个公共的和就是它们的“朋友证号”。例如 123 和 51 就是朋友数,因为 1+2+3 = 5+1 = 6,而 6 就是它们的朋友证号。给定一些整数,要求你统计一下它们中有多少个不同的朋友证号。

输入格式:

输入第一行给出正整数 N。随后一行给出 N 个正整数,数字间以空格分隔。题目保证所有数字小于 10^​4。

输出格式:

首先第一行输出给定数字中不同的朋友证号的个数;随后一行按递增顺序输出这些朋友证号,数字间隔一个空格,且行末不得有多余空格。

输入样例:

8
123 899 51 998 27 33 36 12

输出样例:

4
3 6 9 26

Solution:

将朋友证号作为key值, 建成hash表, 重新遍历一遍就可以输出。

注意点: 用一个max_p可以限定hash表遍历的范围.

#include <cstdio>
#include <cstring>

int id[10050];
char digit[6];

int main() {
int N; scanf("%d", &N);
int cnt = 0, max_p = 0;
while (N--) {
scanf("%s", digit);
int num = 0;
for (int i = 0; i < strlen(digit); i++) {
num += digit[i] - '0';
}

if (!id[num]) {
id[num] = 1;
cnt++;
if (num > max_p) max_p = num;
}
}

int flag = 0;
printf("%d\n", cnt);
for (int i = 0; i <= max_p; i++) {
if (id[i]) {
if (flag) printf(" ");
printf("%d", i);
flag = 1;
}
}
return 0;
}
1…567…18

mituh

179 日志
99 标签
© 2018 mituh
由 Hexo 强力驱动
|
主题 — NexT.Muse v5.1.4