PAT (Advanced Level) Practice

Intro

从入门到入土系列之 PAT 甲级 题库快乐🤣启动。
长期更新ing~

1001 A+B Format

Analysis

题目意思比较简单,给俩数,相加算结果,然后输出的时候每三位一个,隔开,并且负数得在开头输出-

按照题目给出的数字范围:$-10^6 \le a,\ b \le 10^6$,所以可以直接使用int型变量进行相加,然后在输出之前在做数位拆分即可。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <cstdio>
const int MAXN = 10;

int main(int argc, char const *argv[]) {
int a, b, sum;
scanf("%d %d", &a, &b);
sum = a + b;
if(sum < 0) {
putchar('-');
sum = -sum;
}
int len = 0, num[MAXN];
if(sum == 0) {
num[len++] = sum;
}
while(sum) {
num[len++] = sum % 10;
sum /= 10;
}
for(int i = len - 1; i >= 0; i--) {
printf("%d", num[i]);
if(i > 0 && i % 3 == 0) {
putchar(',');
}
}
return 0;
}

贴个 C++ 用字符串处理的思路:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <iostream>
#include <algorithm>
using namespace std;

int main() {
int a, b, c;
cin >> a >> b;
c = a + b;
if(c < 0) {
cout << '-';
c = -c;
}
string str = to_string(c), tmp;
int cnt = 0;
for(int i = str.length() - 1; i >= 0; i--) {
tmp.push_back(str[i]);
cnt++;
if(cnt == 3) {
if(i != 0) tmp += ',';
cnt = 0;
}
}
reverse(tmp.begin(), tmp.end());
cout << tmp;
return 0;
}

不过换个思路,这个题还能更简单:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <iostream>
using namespace std;

int main() {
int a, b, c;
cin >> a >> b;
c = a + b;
if(c < 0) {
cout << '-';
c = -c;
}
if(c >= 1000000) printf("%d,%03d,%03d", c / 1000000, c % 1000000 / 1000, c % 1000);
else if(c >= 1000) printf("%d,%03d", c / 1000, c % 1000);
else printf("%d", c);
return 0;
}

1002 A+B for Polynomials

Analysis

此题是 ZJU 数据结构课程里面的例题了,而且还只是一半的内容,算法思想不难(毕竟只是初中数学的水平,我丢😅),先按照链表来做吧,后面在看看能不能尝试其他方法。一开始偷懒没有将结果构造成一个新的链表,发现测试点5无法通过,改了一会,还是不选择偷懒了...

Code

method 1

用链表做比较繁琐,不过可以锻炼一下链表的基本操作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
/*
test point 5, like this:
2 1 2.4 0 3.2
3 2 2.4 1 2.4 0 -3.2
*/

#include <cstdio>
#include <cstdlib>

typedef struct Polynode* Polynomial;
struct Polynode {
int expo;
double coef;
Polynomial link;
};

Polynomial ReadPoly();
Polynomial Add(Polynomial P1, Polynomial P2);
void Print(Polynomial PP);
int GetNum(Polynomial P);
void Attach(double c, int e, Polynomial *pRear);

int main(int argc, char const *argv[]) {
Polynomial P1 = ReadPoly();
Polynomial P2 = ReadPoly();
Polynomial PP = Add(P1, P2);
int number = GetNum(PP);
if(number) {
printf("%d ", number);
Print(PP);
} else {
printf("%d\n", number);
}
return 0;
}

Polynomial ReadPoly() {
int K;
scanf("%d", &K);
Polynomial P, rear;
P = (Polynomial)malloc(sizeof(struct Polynode));
P->link = NULL;
rear = P;
int e;
double c;
while(K--) {
scanf("%d %lf", &e, &c);
Attach(c, e, &rear);
}
return P;
}

Polynomial Add(Polynomial P1, Polynomial P2) {
Polynomial p1 = P1->link, p2 = P2->link, p, rear;
p = (Polynomial)malloc(sizeof(struct Polynode));
p->link = NULL;
rear = p;
double sum;
while(p1 && p2) {
int temp = p1->expo - p2->expo;
if(temp > 0) {
Attach(p1->coef, p1->expo, &rear);
p1 = p1->link;
} else if(temp == 0) {
sum = p1->coef + p2->coef;
if(sum) {
Attach(sum, p1->expo, &rear);
}
p1 = p1->link;
p2 = p2->link;
} else {
Attach(p2->coef, p2->expo, &rear);
p2 = p2->link;
}
}
if(p1) {
rear->link = p1;
}
if(p2) {
rear->link = p2;
}
return p;
}

void Print(Polynomial PP) {
Polynomial P = PP->link;
while(P) {
if(P->link == NULL) {
printf("%d %.1lf\n", P->expo, P->coef);
} else {
printf("%d %.1lf ", P->expo, P->coef);
}
P = P->link;
}
}

int GetNum(Polynomial P) {
Polynomial p = P->link;
int ret = 0;
while(p) {
ret++;
p = p->link;
}
return ret;
}

void Attach(double c, int e, Polynomial *pRear) {
Polynomial P;
P = (Polynomial)malloc(sizeof(struct Polynode));
P->coef = c;
P->expo = e;
P->link = NULL;
(*pRear)->link = P;
*pRear = P;
}

用 C++ 的特性,简化一下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
#include <iostream>
using namespace std;
typedef struct Node* List;
typedef struct Node* PtrtoNode;
struct Node {
int exp;
double coe;
PtrtoNode next;
Node() { next = nullptr; }
Node(int _exp, double _coe) {
exp = _exp;
coe = _coe;
next = nullptr;
}
};
List createlist(int node_num) {
int exp;
double coe;
List head = new Node;
List L = head;
while(node_num--) {
scanf("%d %lf", &exp, &coe);
head->next = new Node(exp, coe);
head = head->next;
}
head = L;
L = L->next;
delete(head);
return L;
}
int main() {
int k, exp;
double coe;
scanf("%d", &k);
List L, L1, L2;
L1 = createlist(k);
scanf("%d", &k);
L2 = createlist(k);
L = new Node;
List tmp = L;
while(L1 && L2) {
if(L1->exp == L2->exp) {
if(L1->coe + L2->coe != 0) {
L->next = new Node(L1->exp, L1->coe + L2->coe);
L = L->next;
}
L1 = L1->next;
L2 = L2->next;
} else if(L1->exp > L2->exp) {
L->next = L1;
L1 = L1->next;
L = L->next;
} else {
L->next = L2;
L2 = L2->next;
L = L->next;
}
}
if(L1) L->next = L1;
if(L2) L->next = L2;
L = tmp->next;
delete(tmp);
tmp = L;
int cnt = 0;
while(tmp) {
if(tmp->coe != 0) cnt++;
tmp = tmp->next;
}
printf("%d", cnt);
if(cnt) {
while(L) {
printf(" %d %.1lf", L->exp, L->coe);
L = L->next;
}
}
return 0;
}

method 2

实际上,这个题拿数组做,简单了不止一点半点😂。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <cstdio>
void readp(int nums, double *poly) {
int exp;
double coe;
for(int i = 0; i < nums; i++) {
scanf("%d %lf", &exp, &coe);
poly[exp] = coe;
}
}
int main() {
double L1[1005] = {0}, L2[1005] = {0}, L[1005] = {0};
int k1, k2, exp;
double coe;
scanf("%d", &k1);
readp(k1, L1);
scanf("%d", &k2);
readp(k2, L2);
int cnt = 0;
for(int i = 0; i < 1005; i++) {
L[i] = L1[i] + L2[i];
if(L[i] != 0) cnt++;
}
printf("%d", cnt);
if(cnt) {
for(int i = 1000; i >= 0; i--) {
if(L[i] != 0) printf(" %d %.1lf", i, L[i]);
}
}
return 0;
}

1003 Emergency

Analysis

题目大意是给定几个城市之间的地图,城市之间的路有相应的权值,然后给定起始城市和终点城市,问从起始城市到达终点城市的路径有几条,并且这些路径上点权之和最大是多少。

由于题目的实际意义,构造好的图一定是一个无向图,借助 Dijkstra 算法或 Bellman-Ford 算法可以解决这两个问题。

路径条数和点权和的最大值,分别使用一个数组来统计即可。

Code

Dijkstra

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxv = 510;
const int INF = 1000000000;
int n, m, st, ed, G[maxv][maxv], weight[maxv];
int d[maxv], w[maxv] = {0}, num[maxv] = {0};
bool vis[maxv] = {false};
void dijkstra(int s) {
fill(d, d + maxv, INF);
d[s] = 0;
w[s] = weight[s];
num[s] = 1;
for(int i = 0; i < n; i++) {
int u = -1, min = INF;
for(int j = 0; j < n; j++) {
if(vis[j] == false && d[j] < min) {
u = j;
min = d[j];
}
}
if(u == -1) return;
vis[u] = true;
for(int v = 0; v < n; v++) {
if(vis[v] == false && G[u][v] != INF) {
if(d[u] + G[u][v] < d[v]) {
d[v] = d[u] + G[u][v]; //update the distance of each node
w[v] = w[u] + weight[v]; // update the 'hands'
num[v] = num[u]; // update the path for a new reachable node
} else if(d[u] + G[u][v] == d[v]) {
/*only one path can count the 'hands', so the w[v] will
be covered by the sum of last node and its own 'hands' */
if(w[u] + weight[v] > w[v]) {
w[v] = w[u] + weight[v];
}
//but the number of path is not only
num[v] += num[u];
}
}
}
}
}

int main(int argc, char const *argv[]) {
cin >> n >> m >> st >> ed;
for(int i = 0; i < n; i++) {
cin >> weight[i];
}
int u, v;
fill(G[0], G[0] + maxv * maxv, INF);
for(int i = 0; i < m; i++) {
cin >> u >> v;
cin >> G[u][v];
G[v][u] = G[u][v];
}
dijkstra(st);
cout << num[ed] << ' ' << w[ed];
return 0;
}

Bellman-Ford

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#include <iostream>
#include <cstring>
#include <vector>
#include <set>
using namespace std;
struct node {
int v, dis;
node(int _v, int _dis) : v(_v), dis(_dis) {} // constructor
};
const int maxv = 510;
const int inf = 0x3fffffff;
int n, m, st, ed, weight[maxv];
int num[maxv] = {0}, w[maxv] = {0}, d[maxv];
vector<node> Adj[maxv];
set<int> pre[maxv];
bool bellmanford(int s) {
fill(d, d + maxv, inf);
d[s] = 0;
num[s] = 1;
w[s] = weight[s];
for(int i = 0; i < n - 1; i++) {
for(int u = 0; u < n; u++) {
for(int j = 0; j < Adj[u].size(); j++) {
int v = Adj[u][j].v;
int dis = Adj[u][j].dis;
if(d[u] + dis < d[v]) { // more optimal solution
d[v] = d[u] + dis;
w[v] = w[u] + weight[v];
num[v] = num[u];
pre[v].clear(); // attention: pre[v] must be clear firstly
pre[v].insert(u); // save the precursor
} else if(d[u] + dis == d[v]) {
if(w[v] < w[u] + weight[v]) { // update the maximum
w[v] = w[u] + weight[v];
}
pre[v].insert(u); // other shortest path also need save
num[v] = 0; // the number of shortest path has been changed
set<int>::iterator it;
for(it = pre[v].begin(); it != pre[v].end(); it++) {
num[v] += num[*it];
}
}
}
}
}
}
int main(int argc, char const *argv[]) {
cin >> n >> m >> st >> ed;
for(int i = 0; i < n; i++) {
cin >> weight[i];
}
int u, v, dis;
for(int i = 0; i < m; i++) {
cin >> u >> v >> dis;
Adj[u].push_back(node(v, dis));
Adj[v].push_back(node(u, dis));
}
bellmanford(st);
cout << num[ed] << ' ' << w[ed];
return 0;
}

1004 Counting Leaves

Analysis

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
const int maxn = 110;
struct node {
int depth;
vector<int> child;
} Node[maxn];
int n, m, child, seq, maxDepth = -1;
int leaves[maxn] = {0};
void BFS() {
queue<int> q;
q.push(1);
Node[1].depth = 1;
while(!q.empty()) {
int front = q.front();
q.pop();
if(Node[front].depth > maxDepth) {
maxDepth = Node[front].depth;
}
if(Node[front].child.size() != 0) {
for(int i = 0; i < Node[front].child.size(); i++) {
int child = Node[front].child[i];
Node[child].depth = Node[front].depth + 1;
q.push(child);
}
} else {
leaves[Node[front].depth]++;
}
}
}

int main(int argc, char const *argv[]) {
cin >> n >> m;
int k;
for(int i = 0; i < m; i++) {
cin >> seq >> k;
for(int j = 0; j < k; j++) {
cin >> child;
Node[seq].child.push_back(child);
}
}
BFS();
for(int i = 1; i <= maxDepth; i++) {
cout << leaves[i];
if(i < maxDepth) cout << ' ';
}
return 0;
}

1005 Spell It Right

Analysis

题目意思很简单,给一个数字,计算出这个数字每一位上的数字之和,然后用英文的方式分别输出这个和的每一位数字(好吧,有点绕😅)。

与乙级题库的1002很类似,考察数位拆分吧,比较简单。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <cstdio>
const int MAXN = 100 + 5;

char NumberTable[11][10] = {
"zero", "one", "two", "three", "four", "five",
"six", "seven", "eight", "nine", "ten",
};

int main(int argc, char const *argv[]) {
char num[MAXN];
int sum = 0;
scanf("%s", num);
char *p = num;
while(*p != '\0') {
sum += *p++ - '0';
}
int temp = sum, mask = 1;
while(temp > 9) {
temp /= 10;
mask *= 10;
}
while(mask) {
printf("%s", NumberTable[sum / mask]);
if(mask > 9) {
putchar(' ');
}
sum %= mask;
mask /= 10;
}
putchar('\n');
return 0;
}

贴个 C++ 版:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>
#include <unordered_map>
using namespace std;
unordered_map<int, string> num2english = {{0, "zero"}, {1, "one"}, {2, "two"}, {3, "three"},
{4, "four"}, {5, "five"}, {6, "six"}, {7, "seven"}, {8, "eight"}, {9, "nine"}};

int main() {
string str;
cin >> str;
int sum = 0;
for(int i = 0; i < str.length(); i++) {
sum += str[i] - '0';
}
str = to_string(sum);
for(int i = 0; i < str.length(); i++) {
cout << num2english[str[i] - '0'];
if(i != str.length() - 1) cout << ' ';
}
return 0;
}

再补个用 dfs 输出的办法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <iostream>
#include <unordered_map>
using namespace std;
unordered_map<int, string> num2english = {{0, "zero"}, {1, "one"}, {2, "two"}, {3, "three"},
{4, "four"}, {5, "five"}, {6, "six"}, {7, "seven"}, {8, "eight"}, {9, "nine"}};

void dfs(int n) {
if(n / 10 == 0) {
cout << num2english[n % 10];
return;
}
dfs(n / 10);
cout << ' ' << num2english[n % 10];
}
int main() {
string str;
cin >> str;
int sum = 0;
for(int i = 0; i < str.length(); i++) {
sum += str[i] - '0';
}
dfs(sum);
return 0;
}

1006 Sign in and Sign Out

Analysis

题目意思很简单,最先去机房的人开门,最晚出机房的人关门,用学号代替人名,输出最早来和最晚走的人的学号即可。
分析输入数据,1个字符串,6个整型数字,每3个数字为一个时间点,分别代表到来和离开的时间点,既然要找的只是最早和最晚的两个时间点,那么每次寻找时,只要去比较一个时间点即可。
最早来的时间初始化为一天中最后晚的时间(23:59:59),最晚走的时间初始化为一天中最早的时间(00:00:00),注意要分开比较,不能用if-else哦。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#include <cstdio>

struct person{
char ID_number[20];
int start_hh, start_mm, start_ss, end_hh, end_mm, end_ss;
} first, last, temp;

void Init();
bool Earliest(person a, person b);
bool Latest(person a, person b);

int main(int argc, char const *argv[]) {
Init();
int M;
scanf("%d", &M);
while(M--) {
scanf("%s %d:%d:%d %d:%d:%d", temp.ID_number, &temp.start_hh, \
&temp.start_mm, &temp.start_ss, &temp.end_hh, &temp.end_mm, &temp.end_ss);
if(Earliest(temp, first)) {
first = temp;
}
if(Latest(temp, last)) {
last = temp;
}
}
printf("%s %s\n", first.ID_number, last.ID_number);
return 0;
}

void Init() {
first.start_hh = 23;
first.start_mm = first.start_ss = 59;
last.end_hh = last.end_mm = last.end_ss = 0;
}

bool Earliest(person a, person b) {
if(a.start_hh != b.start_hh) return a.start_hh <= b.start_hh;
else if(a.start_mm != b.start_mm) return a.start_mm <= b.start_mm;
else return a.start_ss <= a.start_ss;
}

bool Latest(person a, person b) {
if(a.end_hh != b.end_hh) return a.end_hh >= b.end_hh;
else if(a.end_mm != b.end_mm) return a.end_mm >= b.end_mm;
else return a.end_ss >= b.end_ss;
}

实际上,可以直接使用字符串进行比较得到符合条件的值:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <iostream>
using namespace std;

int main() {
int m;
cin >> m;
string early, late, earliest, latest, tmp, come, leave;
cin >> early >> earliest >> latest;
late = early;
m--;
while(m--) {
cin >> tmp >> come >> leave;
if(come < earliest) {
early = tmp;
earliest = come;
}
if(leave > latest) {
late = tmp;
latest = leave;
}
}
cout << early << ' ' << late;
return 0;
}

1007 Maximum Subsequence Sum

Analysis

Code

DP

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <iostream>
using namespace std;
const int maxn = 10010;
int a[maxn], dp[maxn];
int s[maxn] = {0};
int main(int argc, char const *argv[]) {
int n;
cin >> n;
bool flag = false;
for(int i = 0; i < n; i++) {
cin >> a[i];
if(a[i] >= 0) flag = true;
}
if(flag == false) {
cout << 0 << ' ' << a[0] << ' ' << a[n - 1];
} else {
dp[0] = a[0];
for(int i = 1; i < n; i++) {
if(dp[i - 1] + a[i] > a[i]) {
dp[i] = dp[i - 1] + a[i];
s[i] = s[i - 1];
} else {
dp[i] = a[i];
s[i] = i;
}
}
int k = 0;
for(int i = 1; i < n; i++) {
if(dp[i] > dp[k]) {
k = i;
}
}
cout << dp[k] << ' ' << a[s[k]] << ' ' << a[k];
}
return 0;
}

Online-Processing

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <iostream>
using namespace std;
const int maxk = 10010;
int main(int argc, char *argv[]) {
int k, arr[maxk] = {0};
cin >> k;
for(int i = 0; i < k; i++) {
cin >> arr[i];
}
int ThisSum = 0, MaxSum = -1;
int left = 0, right = k - 1, temp_left = 0;
for(int i = 0; i < k; i++) {
ThisSum += arr[i];
if(ThisSum > MaxSum) {
MaxSum = ThisSum;
right = i;
left = temp_left;
} else if(ThisSum < 0) {
ThisSum = 0;
temp_left = i + 1;
}
}
if(MaxSum < 0) cout << 0 << ' ' << arr[left] << ' ' << arr[right];
else cout << MaxSum << ' ' << arr[left] << ' ' << arr[right];
return 0;
}

1008 Elevator

Analysis

题目大意是给定电梯移动和等待的时长,再按照题目给定的停留顺序,计算出电梯在这个过程中需要的总时间。
以样例为例:

  1. 初始为0层,到2层,时长为:$2 \times 6 = 12\ s$,再加上等待的$5s$,总计$17s$
  2. 从2层到3层,时长为:$1 \times 6 = 6\ s$,再加上等待的$5s$,总计$11s$
  3. 从3层到1层,时长为:$2 \times 4 = 8\ s$,再加上等待的$5s$,总计$13s$
  4. 合计为:$17 + 11 + 13 = 41\ s$

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <cstdio>

int main(int argc, char const *argv[]) {
int n, array[105] = {0};
scanf("%d", &n);
for(int i = 0; i < n; i++) {
scanf("%d", &array[i]);
}
int total = 0, last = 0;
for(int i = 0; i < n; i++) {
if(array[i] == last) {
total += 5;
} else if(array[i] > last) {
total += ((array[i] - last) * 6 + 5);
} else {
total += ((last - array[i]) * 4 + 5);
}
last = array[i];
}
printf("%d\n", total);
return 0;
}

1009 Product of Polynomials

Analysis

此题也是 ZJU 数据结构课程里面的例题,算是另一半了,与 1002 是类似的,只不过 1002 是加法,这个是乘法,还是先用链表做吧。

Code

method 1

链表做法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
#include <cstdio>
#include <cstdlib>

typedef struct PolyNode *Polynomial;
struct PolyNode {
double coef;
int expon;
Polynomial link;
};

void Attach(double c, int e, Polynomial *pRear);
Polynomial ReadPoly();
Polynomial Mult(Polynomial P1, Polynomial P2);
void PrintPoly(Polynomial P);
int Compare(int a, int b);
int GetNum(Polynomial P);

int main(int argc, char const *argv[]){
Polynomial P1, P2, PP, PS;
P1 = ReadPoly();
P2 = ReadPoly();
PP = Mult(P1, P2);
int numbers = GetNum(PP);
if(numbers) {
printf("%d ", numbers);
PrintPoly(PP);
} else {
printf("%d\n");
}
return 0;
}

void Attach(double c, int e, Polynomial *pRear) {
Polynomial P;
P = (Polynomial)malloc(sizeof(struct PolyNode));
P->coef = c;
P->expon = e;
P->link = NULL;
(*pRear)->link = P;
*pRear = P;
}

Polynomial ReadPoly() {
Polynomial P, Rear, t;
int e, K;
double c;
scanf("%d", &K);
P = (Polynomial)malloc(sizeof(struct PolyNode));
P->link = NULL;
Rear = P;
while(K--) {
scanf("%d %lf", &e, &c);
Attach(c, e, &Rear);
}
t = P;
P = P->link;
free(t);
return P;
}

Polynomial Mult(Polynomial P1, Polynomial P2) {
Polynomial P, Rear, t1, t2, t;
int e;
double c;
if(!P1 || !P2) return NULL;
t1 = P1;
t2 = P2;
P = (Polynomial)malloc(sizeof(struct PolyNode));
P->link = NULL;
Rear = P;
while(t1) {
t2 = P2;
Rear = P;
while(t2) {
e = t1->expon + t2->expon;
c = t1->coef * t2->coef;
while(Rear->link && Rear->link->expon > e) {
Rear = Rear->link;
}
if(Rear->link && Rear->link->expon == e) {
if(Rear->link->coef + c) {
Rear->link->coef += c;
} else {
t = Rear->link;
Rear->link = t->link;
free(t);
}
} else {
t = (Polynomial)malloc(sizeof(struct PolyNode));
t->coef = c;
t->expon = e;
t->link = Rear->link;
Rear->link = t;
Rear = Rear->link;
}
t2 = t2->link;
}
t1 = t1->link;
}
t2 = P;
P = P->link;
free(t2);
return P;
}

void PrintPoly(Polynomial P) {
int flag = 0;
while(P) {
if(!flag){
flag = 1;
} else {
printf(" ");
}
printf("%d %.1lf", P->expon, P->coef);
P = P->link;
}
printf("\n");
}

int Compare(int a, int b) {
return a > b ? 1 : a == b ? 0 : -1;
}

int GetNum(Polynomial P) {
Polynomial p = P;
int ret = 0;
while(p) {
ret++;
p = p->link;
}
return ret;
}

用 C++ 的特性简化一下,删除不需要的部分:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
#include <iostream>
using namespace std;
typedef struct Node* List;
typedef struct Node* PtrtoNode;
struct Node {
int exp;
double coe;
PtrtoNode next;
Node() { next = nullptr; }
Node(int _exp, double _coe) {
exp = _exp;
coe = _coe;
next = nullptr;
}
};
List createlist(int node_num) {
int exp;
double coe;
List head = new Node;
List L = head;
while(node_num--) {
scanf("%d %lf", &exp, &coe);
head->next = new Node(exp, coe);
head = head->next;
}
head = L;
L = L->next;
delete(head);
return L;
}
int main() {
int k;
scanf("%d", &k);
List L1 = createlist(k);
scanf("%d", &k);
List L2 = createlist(k);
List L = new Node, rear, t1 = L1, t2 = L2, t;
rear = L;
int exp_tmp;
double coe_tmp;
while(t1) {
t2 = L2;
rear = L;
while(t2) {
exp_tmp = t1->exp + t2->exp;
coe_tmp = t1->coe * t2->coe;
while(rear->next && rear->next->exp > exp_tmp) {
rear = rear->next;
}
if(rear->next && rear->next->exp == exp_tmp) {
if(rear->next->coe + coe_tmp) rear->next->coe += coe_tmp;
else {
t = rear->next;
rear->next = t->next;
delete(t);
}
} else {
t = new Node(exp_tmp, coe_tmp);
t->next = rear->next;
rear->next = t;
rear = rear->next;
}
t2 = t2->next;
}
t1 = t1->next;
}
t = L;
L = L->next;
delete(t);
int cnt = 0;
t = L;
while(t) {
cnt++;
t = t->next;
}
printf("%d", cnt);
if(cnt) {
t = L;
while(t) {
printf(" %d %.1lf", t->exp, t->coe);
t = t->next;
}
}
return 0;
}

method 2

数组做法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include <cstdio>
void readp(int nums, double *poly) {
int exp;
double coe;
for(int i = 0; i < nums; i++) {
scanf("%d %lf", &exp, &coe);
poly[exp] = coe;
}
}
int main() {
double L1[1005] = {0}, L2[1005] = {0}, L[2010] = {0};
int k1, k2, exp;
double coe;
scanf("%d", &k1);
readp(k1, L1);
scanf("%d", &k2);
readp(k2, L2);
for(int i = 0; i < 1001; i++) {
for(int j = 0; j < 1001; j++) {
exp = i + j;
coe = L1[i] * L2[j];
L[exp] += coe;
}
}
int cnt = 0;
for(int i = 0; i <= 2000; i++) {
if(L[i] != 0) cnt++;
}
printf("%d", cnt);
for(int i = 2000; i >= 0; i--) {
if(L[i] != 0) printf(" %d %.1lf", i, L[i]);
}
return 0;
}

1010 Radix

Analysis

这个题的题意说的比较模糊,所以不太好寻找思路。
先分析一下题目意思,给定N1N2tagradix四个数字;若当tag为1时,radix的值就是N1的进制数,tag为2时,radix的值就是N2的进制数(一般针对这种情况,最好交换下N1N2的值,再统一处理)。

紧接着,题目要求判断N1N2是否相等,由于题目给定的两个数字的进制不相同,所以还必须要转换后进行判断。与其这样,不如直接将能确定进制的那个数转化为十进制数,然后与另一个数的每一个不同的进制单位下转换为十进制数后值进行比较,若相等,则这两个数相等(只要在一种进制单位下,两个数相等,那么在其他任意进制单位下,这两个数不管如何变化都是相等的)。

明白题意后,就得开始打码了。由于题目给定的radix没有限制范围,所以转换后的十进制数是有可能溢出的(long long也会),所以使用字符串来存储数字

紧接着,按照前面的思路,先构造字符0 - 9a - z的十进制数对应表,方便调用。另外,不管tag的值如何,对N1N2进行处理,默认N1是进制确定的数。在开始对N2进行进制转换之前,要先确定其可能的进制范围,这个结果就是:以其字符最大值为下界,N1的十进制数值为上界。在这个进制范围内,一个一个去枚举显然是很慢的,所以使用二分法是一个很不错的选择。

注意:

  1. 使用二分法时,只需要找到满足条件:N1的十进制数相等的数即可,此时得返回进制数
  2. 针对数据的溢出情况,一旦结果为负,就可以判断为溢出,此时N2在这个进制下的转换出来的十进制数肯定是大于N1的十进制数的。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
LL Map[256];
LL inf = (1LL << 63) - 1;

void Init() {
for(char c = '0'; c <= '9'; c++) {
Map[c] = c - '0';
}
for(char c = 'a'; c <= 'z'; c++) {
Map[c] = c - 'a' + 10;
}
}

LL ConvertNum10(char *a, LL radix, LL t) {
LL ret = 0;
for(int i = 0; a[i] != '\0'; i++) {
ret = ret * radix + Map[a[i]];
if(ret < 0 || ret > t) {
ret = -1;
break;
}
}
return ret;
}

int cmp(char *N2, LL radix, LL t) {
int len = strlen(N2);
LL num = ConvertNum10(N2, radix, t);
if(num < 0) return 1;
if(t > num) return -1;
else if(t == num) return 0;
else return 1;
}

LL BinarySearch(char *N2, LL left, LL right, LL t) {
LL mid;
while(left <= right) {
mid = (left + right) / 2;
int flag = cmp(N2, mid, t);
if(flag == 0) return mid;
else if(flag == -1) left = mid + 1;
else right = mid - 1;
}
return - 1;
}

int FindLargestDigit(char *N2) {
int ans = -1, len = strlen(N2);
for(int i = 0; i < len; i++) {
if(Map[N2[i]] > ans) {
ans = Map[N2[i]];
}
}
return ans + 1;
}

char N1[20], N2[20], temp[20];
int tag, radix;
int main(int argc, char const *argv[]) {
Init();
scanf("%s %s %d %d", N1, N2, &tag, &radix);
if(tag == 2) {
strcpy(temp, N1);
strcpy(N1, N2);
strcpy(N2, temp);
}
LL t = ConvertNum10(N1, radix, inf);
LL low = FindLargestDigit(N2);
LL high = max(low, t) + 1;
LL ans = BinarySearch(N2, low, high, t);
if(ans == -1) {
printf("Impossible\n");
} else {
printf("%lld\n", ans);
}
return 0;
}

1011 World Cup Betting

Analysis

题目意思很明确,三局比赛,给出每局的赔率,默认每次都赌对,问怎样买收益最多。
很简单,每次买赔率最大的就好啦~然后还有一个麻烦的地方,就是要输出每局赔率最大的是哪一种局,即:获胜(Win)、平局(Tie)和失败(Lose),先保存每次的下标,然后写个函数转换一下就好了。至于收益的计算方法,按照题目给定的公式算就好了。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include <cstdio>

char change(int index);

int main(int argc, char const *argv[]) {
double Bet[3][3], Profit = 0.0;
for(int i = 0; i < 3; i++) {
scanf("%lf %lf %lf", &Bet[i][0], &Bet[i][1], &Bet[i][2]);
}
int max_index[3];
double max[3] = {0.0};
for(int i = 0; i < 3; i++) {
for(int j = 0; j < 3; j++) {
if(max[i] < Bet[i][j]) {
max[i] = Bet[i][j];
max_index[i] = j;
}
}
}

Profit = (max[0] * max[1] * max[2] * 0.65 - 1.0) * 2.0;
printf("%c %c %c %.2lf\n", change(max_index[0]), change(max_index[1]), change(max_index[2]), Profit);
return 0;
}

char change(int index) {
char ret;
switch(index) {
case 0:
ret = 'W';
break;
case 1:
ret = 'T';
break;
case 2:
ret = 'L';
break;
}
return ret;
}

贴一个简化版:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <cstdio>
int main() {
double turns[3][3], max, maxproduct = 1.0;
char ans[3];
for(int i = 0; i < 3; i++) {
max = -1000;
for(int j = 0; j < 3; j++) {
scanf("%lf", &turns[i][j]);
if(max < turns[i][j]) {
max = turns[i][j];
if(j == 1) ans[i] = 'T';
else if(j == 2) ans[i] = 'L';
else ans[i] = 'W';
}
}
maxproduct *= max;
}
double maxprofit = 0.0;
maxprofit = (maxproduct * 0.65 - 1) * 2;
for(int i = 0; i < 3; i++) {
printf("%c ", ans[i]);
}
printf("%.2lf", maxprofit);
return 0;
}

1012 The Best Rank

Analysis

给出每个学生的各科成绩,计算其平均分,并根据他们的成绩进行排序;然后查找指定学号的学生的成绩,输出其排名最优的成绩和科目名称。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#include <cstdio>
#include <algorithm>
using namespace std;

const int MAXN = 2000 + 5;
struct student {
int id, grade[4];
} stu[MAXN];
char course[4] = {'A', 'C', 'M', 'E'};
int Rank[10000000][4] = {0};
int now;
bool cmp(student a, student b);

int main(int argc, char const *argv[]) {
int N, M;
scanf("%d %d", &N, &M);
for(int i = 0; i < N; i++) {
scanf("%d %d %d %d", &stu[i].id, &stu[i].grade[1], &stu[i].grade[2],
&stu[i].grade[3]);
stu[i].grade[0] = (stu[i].grade[1] + stu[i].grade[2] + stu[i].grade[3]) / 3;
}
for(now = 0; now < 4; now++) {
sort(stu, stu + N, cmp);
Rank[stu[0].id][now] = 1;
for(int i = 1; i < N; i++) {
if(stu[i].grade[now] == stu[i - 1].grade[now]) {
Rank[stu[i].id][now] = Rank[stu[i - 1].id][now];
} else {
Rank[stu[i].id][now] = i + 1;
}
}
}
int query;
while(M--) {
scanf("%d", &query);
if(Rank[query][0] == 0) {
printf("N/A\n");
} else {
int k = 0;
for(int j = 0; j < 4; j++) {
if(Rank[query][j] < Rank[query][k]) {
k = j;
}
}
printf("%d %c\n", Rank[query][k], course[k]);
}
}
return 0;
}

bool cmp(student a, student b) {
return a.grade[now] > b.grade[now];
}

重新写了一下,求每个学生的各科排名时,不再开那么大的数组了,但是会有额外的查找时间开销(也能 AC):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include <iostream>
#include <algorithm>
using namespace std;
struct student {
string id;
int grade[4];
int rank[4];
} stu[2005];
char species[5] = "ACME";
int now;
int main() {
int N, M, c, m, e;
cin >> N >> M;
string str;
for(int i = 0; i < N; i++) {
cin >> str >> c >> m >> e;
stu[i].id = str;
stu[i].grade[1] = c, stu[i].grade[2] = m, stu[i].grade[3] = e;
stu[i].grade[0] = (c + m + e) / 3;
}
for(now = 0; now < 4; now++) {
sort(stu, stu + N, [](student a, student b){
return a.grade[now] > b.grade[now];
});
stu[0].rank[now] = 1;
for(int j = 1; j < N; j++) {
if(stu[j].grade[now] == stu[j - 1].grade[now]) stu[j].rank[now] = stu[j - 1].rank[now];
else stu[j].rank[now] = j + 1;
}
}
for(int i = 0; i < M; i++) {
cin >> str;
int index = -1;
for(int i = 0; i < N; i++) {
if(stu[i].id == str) {
index = i;
break;
}
}
if(index == -1) cout << "N/A" << endl;
else {
int k = 0;
for(int i = 1; i < 4; i++) {
if(stu[index].rank[i] < stu[index].rank[k]) k = i;
}
cout << stu[index].rank[k] << ' ' << species[k] << endl;
}
}
return 0;
}

1013 Battle Over Cities

Analysis

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
/* method 1: use union-find set
*/
#include <iostream>
#include <vector>
using namespace std;
const int maxn = 1010;
vector<int> G[maxn];
int father[maxn];
bool vis[maxn];
int n, m, k;
int findFather(int x) {
int a = x;
while(x != father[x]) {
x = father[x];
}
while(a != father[a]) {
int z = a;
a = father[a];
father[z] = x;
}
return x;
}
void Union(int a, int b) {
int faA = findFather(a);
int faB = findFather(b);
if(faA != faB) {
father[faA] = faB;
}
}
void init() {
for(int i = 1; i < maxn; i++) {
father[i] = i;
vis[i] = false;
}
}
int main(int argc, char const *argv[]) {
cin >> n >> m >> k;
for(int i = 0; i < m; i++) {
int a, b;
cin >> a >> b;
G[a].push_back(b);
G[b].push_back(a);
}
int currentPoint;
for(int query = 0; query < k; query++) {
cin >> currentPoint;
init();
for(int i = 1; i <= n; i++) {
for(int j = 0; j < G[i].size(); j++) {
int u = i, v = G[i][j];
if(u == currentPoint || v == currentPoint) continue;
Union(u, v);
}
}
int block = 0;
for(int i = 1; i <= n; i++) {
if(i == currentPoint) continue;
int fa_i = findFather(i);
if(vis[fa_i] == false) {
block++;
vis[fa_i] = true;
}
}
cout << block - 1 << endl;
}
return 0;
}


/*method 2: use DFS
#include <iostream>
#include <cstring>
#include <vector>
using namespace std;
const int maxn = 1010;
vector<int> G[maxn];
bool vis[maxn] = {false};

int currentPoint;
int n, m, k;
void dfs(int v) {
if(v == currentPoint) return;
vis[v] = true;
for(int i = 0; i < G[v].size(); i++) {
if(vis[G[v][i]] == false) {
dfs(G[v][i]);
}
}
}
int main(int argc, char const *argv[]) {
cin >> n >> m >> k;
for(int i = 0; i < m; i++) {
int a, b;
cin >> a >> b;
G[a].push_back(b);
G[b].push_back(a);
}
for(int query = 0; query < k; query++) {
cin >> currentPoint;
memset(vis, false, sizeof(vis));
int block = 0;
for(int i = 1; i <= n; i++) {
if(i != currentPoint && vis[i] == false) {
dfs(i);
block++;
}
}
cout << block - 1 << endl;
}

return 0;
}
*/

1015 Reversible Primes

Analysis

题目大意是给定两个整数NDN是十进制下的整数,D是进制数,判断N和将N转换为D进制下的数是否都是素数。若是,输出Yes,反之输出No

考察进制转换和素数的判断。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include <cstdio>
#include <cmath>

int Reverse(int number, int radix) {
int a[32], temp = number, count = 0, ret = 0;
while(temp) {
a[count++] = temp % radix;
temp /= radix;
}
for(int i = 0; i < count; i++) {
ret = ret * radix + a[i];
}
return ret;
}

bool isPrime(int n) {
if(n <= 1 || (n % 2 == 0 && n != 2)) {
return false;
} else {
for(int i = 3; i <= sqrt(n); i += 2) {
if(n % i == 0) return false;
}
}
return true;
}

int main(int argc, char const *argv[]) {
int n, d;
while(1) {
scanf("%d", &n);
if(n < 0) break;
scanf("%d", &d);
if(isPrime(n) && isPrime(Reverse(n, d))) {
printf("Yes\n");
} else {
printf("No\n");
}
}
return 0;
}

贴个 C++ 版:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <iostream>
#include <cmath>
#include <vector>
using namespace std;
bool isprime(int n) {
if(n <= 1) return false;
else {
for(int i = 2; i <= sqrt(n); i++) {
if(n % i == 0) return false;
}
return true;
}
}
int main() {
int n, d;
while(true) {
cin >> n;
if(n < 0) break;
cin >> d;
if(!isprime(n)) cout << "No" << endl;
else {
vector<int> digits;
int tmp = n;
while(tmp) {
int r = tmp % d;
digits.push_back(r);
tmp /= d;
}
tmp = 0;
for(int i = 0; i < digits.size(); i++) {
tmp = tmp * d + digits[i];
}
if(isprime(tmp)) cout << "Yes" << endl;
else cout << "No" << endl;
}
}
return 0;
}

1016 Phone Bills

Analysis

先分析一下输入,包含名称、时间和状态,其中名称和状态是以字符串的形式输入的,而时间则是十进制数字。这里要立刻反应过来,不能用题目字符串来表示状态,应该换成数字来表示。至于,最开始输入的费率表,使用一个整型数组来存储,使用的时候进行调用就好。

接下来,需要对输入的数据进行排序,优先级最大的排序依据就是名称,按照字典序来排列,注意字符串需要用strcmp函数来进行比较;其次,相同名称的元素按照时间的先后进行排列就好了。

接着再来看输出,首先要输出的是客户的名称和其话费账单所处的月份;第二行开始输出客户的话费账单的开始时间和结束时间,然后输出当前账单的总时长和费用,注意费用为浮点型;所有账单都输出完毕后,最后一行输出客户总话费。

大致清楚之后,如何去计算话费呢?根据题目,输入的每一项必须是配对的on-lineoff-line才能组成一个合法的账单,并且必须要是连续、相邻的才能是一对(这个条件很重要)。读懂这个条件后,计算时间就比较简单了,让开始时间一直增加到结束时间,统计好分钟数既可得到经历的时间,然后计算总费用。注意,给定的费率是cents/minute,最后得转化为dollar,除以100即可。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
#include <cstdio> 
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXN = 1000 + 5;

struct record{
char name[25];
int month, day, hour, minute;
bool status;
} rec[MAXN], temp;
int rate[25] = {0};

bool cmp(record a, record b);
void get_time(int on, int off, int &time, int &money);

int main(int argc, char const *argv[]) {
for(int i = 0; i < 24; i++) {
scanf("%d", rate + i);
}
int N;
scanf("%d", &N);
char line[10];
for(int i = 0; i < N; i++) {
scanf("%s %d:%d:%d:%d", rec[i].name, &rec[i].month, &rec[i].day, &rec[i].hour, &rec[i].minute);
scanf("%s", line);
if(!strcmp(line, "on-line")) {
rec[i].status = true;
} else {
rec[i].status = false;
}
}
sort(rec, rec + N, cmp);
int on = 0, off, next;
while(on < N) {
int needPrint = 0;
next = on;
// fint the next customer, and check the current customer has paired 'on-line' and 'off-line' or not
while(next < N && strcmp(rec[next].name, rec[on].name) == 0) {
if(needPrint == 0 && rec[next].status == true) {
needPrint = 1;
} else if(needPrint == 1 && rec[next].status == false) {
needPrint = 2;
}
next++;
}
//the current customer has not paired 'on-line' and 'off-line', skip this customer
if(needPrint < 2) {
on = next;
continue;
}
//calculate the money for current customer
int Total = 0;
printf("%s %02d\n", rec[on].name, rec[on].month);
while(on < next) {
//find the paired 'on-line' and 'off-line'
while(on < next - 1 && !(rec[on].status == true && rec[on + 1].status == false)) {
on++;
}
off = on + 1;
if(off == next) {
on = next;
break;
}
printf("%02d:%02d:%02d ", rec[on].day, rec[on].hour, rec[on].minute);
printf("%02d:%02d:%02d ", rec[off].day, rec[off].hour, rec[off].minute);
int time = 0, money = 0;
get_time(on, off, time, money);
Total += money;
printf("%d $%.2lf\n", time, money / 100.0);
on = off + 1;
}
printf("Total amount: $%.2lf\n", Total / 100.0);
}
return 0;
}

bool cmp(record a, record b) {
if(strcmp(a.name, b.name)) return strcmp(a.name, b.name) < 0;
else if(a.month != b.month) return a.month < b.month;
else if(a.day != b.day) return a.day < b.day;
else if(a.hour != b.hour) return a.hour < b.hour;
else return a.minute < b.minute;
}

void get_time(int on, int off, int &time, int &money) {
temp = rec[on];
while(temp.day < rec[off].day || temp.hour < rec[off].hour || temp.minute < rec[off].minute) {
time++;
money += rate[temp.hour];
temp.minute++;
if(temp.minute >= 60) {
temp.minute = 0;
temp.hour++;
}
if(temp.hour >= 24) {
temp.hour = 0;
temp.day++;
}
}
}

1018 Public Bike Management

Analysis

题目背景类似现在的共享单车,这种公共设施服务有一个管理中心,本题叫做 Public Bike Management Center,简称 PMBC,而这个 PMBC 会调整每个停靠站点的自行车数目从而达到“完美”状态,这种“完美”状态是指停靠数量为该站点最大容量的一半。

题目给定各个站点距离 PMBC 的距离、每个停靠站点当前的停靠数量和需要投放自行车的站点,要求输出完成投放工作需要携带的最小自行车数目、完成投放工作的最短路径和剩余带回的车数,注意路径中的站点如果不是完美状态,也需要调整为完美状态。

题目的第一要求是最短路径,借助 Dijkstra 算法可以解决这个问题,再利用动态数组保存好每一条最短路径,然后借助 DFS 来计算题目要求的所携带的最小自行车数目及剩余带回的车数。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
#include <iostream>
#include <cstring>
#include <cmath>
#include <vector>
using namespace std;
const int maxv = 510;
const int inf = 0x3fffffff;
int Cmax, n, m, sp, G[maxv][maxv], weight[maxv];
int d[maxv], minneed = inf, minremain = inf;
bool vis[maxv] = {false};
vector<int> pre[maxv], tempath, path;
void dijkstra(int s) {
fill(d, d + maxv, inf);
d[s] = 0;
for(int i = 0; i <= n; i++) {
int u = -1, min = inf;
for(int j = 0; j <= n; j++) {
if(vis[j] == false && d[j] < min) {
min = d[j];
u = j;
}
}
if(u == -1) return;
vis[u] = true;
for(int v = 0; v <= n; v++) {
if(vis[v] == false && G[u][v] != inf) {
if(d[v] > d[u] + G[u][v]) {
d[v] = d[u] + G[u][v];
pre[v].clear();
pre[v].push_back(u);
} else if(d[v] == d[u] + G[u][v]) {
pre[v].push_back(u);
}
}
}
}
}
void dfs(int v) {
if(v == 0) {
tempath.push_back(v);
int need = 0, remain = 0;
for(int i = tempath.size() - 1; i >= 0; i--) {
int id = tempath[i];
if(weight[id] > 0) {
remain += weight[id];
} else {
if(remain + weight[id] > 0) {
remain += weight[id];
} else {
need += abs(remain + weight[id]);
remain = 0;
}
}
}
if(need < minneed) {
minneed = need;
minremain = remain;
path = tempath;
} else if(need == minneed && remain < minremain) {
minremain = remain;
path = tempath;
}
tempath.pop_back();
return;
}
tempath.push_back(v);
for(int i = 0; i < pre[v].size(); i++) {
dfs(pre[v][i]);
}
tempath.pop_back();
}
int main(int argc, char const *argv[]) {
cin >> Cmax >> n >> sp >> m;
fill(G[0], G[0] + maxv * maxv, inf);
for(int i = 1; i <= n; i++) {
cin >> weight[i];
weight[i] -= Cmax / 2; //preprocessing: make it 'perfect'
}
int u, v, dis;
for(int i = 0; i < m; i++) {
cin >> u >> v >> dis;
G[u][v] = G[v][u] = dis;
}
dijkstra(0);
dfs(sp);
cout << minneed << ' ';
for(int i = path.size() - 1; i >=0; i--) {
cout << path[i];
if(i > 0) cout << "->";
}
cout << ' ' << minremain;
return 0;
}

1019 General Palindromic Number

Analysis

此题属于结合了进制转换回文序列判断的混合题目。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include <cstdio>

bool PalindromicNum(long long *digits, long long count);

int main(int argc, char const *argv[]) {
long long N, b, count = 0, digits[50] = {0};
scanf("%lld %lld", &N, &b);
while(N) {
digits[count++] = N % b;
N /= b;
}
count--;
if(PalindromicNum(digits, count)) {
printf("Yes\n");
} else {
printf("No\n");
}
for(; count > 0; count--) {
printf("%lld ", digits[count]);
}
printf("%lld\n", digits[count]);
return 0;
}

bool PalindromicNum(long long *digits, long long count) {
bool flag = true;
int i, j;
if(count % 2 == 0) {
i = j = count / 2;
} else {
i = count / 2;
j = i + 1;
}
for(; i >= 0 && j <= count; i--, j++) {
if(digits[i] != digits[j]) {
flag = false;
break;
}
}
return flag;
}

贴个 C++ 版,简化了一下回文的判断过程:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <iostream>
#include <vector>
using namespace std;

int main() {
int n, k;
cin >> n >> k;
if(n == 0) {
cout << "Yes\n" << 0;
} else {
vector<int> digits;
while(n) {
digits.push_back(n % k);
n /= k;
}
int size = digits.size();
bool flag = true;
for(int i = 0; i < size / 2; i++) {
if(digits[i] != digits[size - i - 1]) {
flag = false;
break;
}
}
if(flag) cout << "Yes\n";
else cout << "No\n";
for(int i = size - 1; i >= 0; i--) {
cout << digits[i];
if(i > 0) cout << ' ';
}
}
return 0;
}

1020 Tree Traversals

Analysis

题目大意,给定两个树的中序遍历和后序遍历,求其层次遍历。

此题属于树的常规题型,思路是利用中序遍历和后序遍历建树,然后再借助 BFS 进行层次遍历,并输出层次遍历序列。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#include <cstdio>
#include <queue>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 50;
struct node {
int data;
node *lchild;
node *rchild;
};
int pre[maxn], in[maxn], post[maxn];
int n;

node *create(int postL, int postR, int inL, int inR) {
if(postL > postR) {
return NULL;
}
node *root = new node;
root->data = post[postR];
int k;
for(k = inL; k <= inR; k++) {
if(in[k] == post[postR]) {
break;
}
}
int numLeft = k - inL;
root->lchild = create(postL, postL + numLeft - 1, inL, k - 1);
root->rchild = create(postL + numLeft, postR - 1, k + 1, inR);
return root;
}

int num = 0;
void BFS(node *root) {
queue<node*> q;
q.push(root);
while(!q.empty()) {
node *now = q.front();
q.pop();
printf("%d", now->data);
num++;
if(num < n) printf(" ");
if(now->lchild != NULL) q.push(now->lchild);
if(now->rchild != NULL) q.push(now->rchild);
}
}

int main(int argc, char const *argv[]) {
scanf("%d", &n);
for(int i = 0; i < n; i++) {
scanf("%d", &post[i]);
}
for(int i = 0; i < n; i++) {
scanf("%d", &in[i]);
}
node *root = create(0, n - 1, 0, n - 1);
BFS(root);
return 0;
}

1022 Digital Library

Analysis

题目背景是数字图书馆的检索功能,要求大致模拟一下这个功能。

按照题目的要求,输出书名时,需要按序输出,比起构造新的数据结构后使用sort函数来完成这项操作,不如直接借助set。而在查询时,是通过字符串来进行的查询,使用map建立映射后,就可以类似散列一样进行查询。

综合上述的两种需求后,好在map是支持stringset的映射的,所以直接使用即可。

由于关键字key是一个一个给出的,所以需要一个一个输入并统计,依据cinscanf输入字符串的特性,可以很方便的单个读入,并使用getchar读取回车符结束循环。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include <iostream>
#include <string>
#include <map>
#include <set>
using namespace std;
map<string, set<int> > mpTitle, mpAuthor, mpKey, mpPub, mpYear;
void query(map<string, set<int> > &mp, string &str) {
if(mp.find(str) == mp.end()) printf("Not Found\n");
else {
for(set<int>::iterator it = mp[str].begin(); it != mp[str].end(); it++) {
printf("%07d\n", *it);
}
}
}

int main(int argc, char const *argv[]) {
int n, m, id, type;
string title, author, key, pub, year;
scanf("%d", &n);
while(n--) {
scanf("%d", &id);
char c = getchar();
getline(cin, title);
mpTitle[title].insert(id);
getline(cin, author);
mpAuthor[author].insert(id);
while(cin >> key) {
mpKey[key].insert(id);
c = getchar();
if(c == '\n') break;
}
getline(cin, pub);
mpPub[pub].insert(id);
getline(cin, year);
mpYear[year].insert(id);
}
string temp;
cin >> m;
while(m--) {
scanf("%d: ", &type);
getline(cin, temp);
cout << type << ": " << temp << endl;
if(type == 1) query(mpTitle, temp);
else if(type == 2) query(mpAuthor, temp);
else if(type == 3) query(mpKey, temp);
else if(type == 4) query(mpPub, temp);
else query(mpYear, temp);
}
return 0;
}

查询函数可以写的简单点:

1
2
3
4
5
6
7
8
void query(map<string, set<int>>& mp, string &tmp) {
if(!mp.count(tmp)) printf("Not Found\n");
else {
for(auto &i: mp[tmp]) {
printf("%07d\n", i);
}
}
}

这个题的难点不在算法的设计上,而是在对数据的处理上。为了能更简单的完成这个事情,就需要对 STL 容器、输入输出函数及其他 API 的用法很熟悉。

1023 Have Fun with Numbers

Analysis

题目大意是给一个不超过20位的整数,将这个整数翻倍后,判断组成这个新整数的所有数字是否与原来的数字相同。若是,输出Yes;反之,输出No。注意,无论是否符合都需要输出翻倍后的新数字。

由于题目明确说了给定的数字位数不超过20位,但是long long只能到19位,所以直接使用数组来存储数字,然后利用数组来模拟乘以2。

然后判断两个数字的所有位数字的出现次数是否一致即可(利用散列的思想会比较方便)。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#include <stdio.h>

int Compare(int *original, int *now, int number);

int main(int argc, char const *argv[]) {
char Num[22];
int original[22], now[22], original_occurrence[10] = {0}, now_occurrence[10] = {0};
scanf("%s", Num);
char *p = Num;
int i = 0, j, k, temp = 0, flag = 0;
//conver the string to an array(int)
while(*p != '\0') {
original[i++] = *p++ - '0';
}
//count the occurrence of the original number
for(j = 0; j < i; j++) {
original_occurrence[original[j]]++;
}
//imitate multiplication
for(k = 0, j = i - 1; j >= 0; j--, k++) {
now[k] = (original[j] * 2 + temp) % 10;
temp = original[j] * 2 / 10;
}
if(temp) {
now[k] = temp;
} else {
k -= 1;
}
//count the new number
for(j = 0; j <= k; j++) {
now_occurrence[now[j]]++;
}
flag = Compare(original_occurrence, now_occurrence, 10);
//print
if(flag) {
printf("Yes\n");
} else {
printf("No\n");
}
for(j = k; j > 0; j--) {
printf("%d", now[j]);
}
printf("%d\n", now[j]);
return 0;
}

int Compare(int *original, int *now, int number) {
int i, j, ret = 1;
for(i = 0; i < number; i++) {
if(original[i] != now[i]) {
ret = 0;
break;
}
}
return ret;
}

贴个 C++ 版:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int main() {
string num;
cin >> num;
vector<int> n, dn;
for(int i = num.size() - 1; i >= 0; i--) {
n.push_back(num[i] - '0');
}
int carry = 0;
for(int i = 0; i < n.size(); i++) {
dn.push_back((2 * n[i] + carry) % 10);
carry = 2 * n[i] / 10;
}
if(carry > 0) dn.push_back(carry);
string ans;
for(int i = dn.size() - 1; i >= 0; i--) {
ans.push_back(dn[i] + '0');
}
sort(n.begin(), n.end());
sort(dn.begin(), dn.end());
if(n == dn) cout << "Yes" << endl;
else cout << "No" << endl;
cout << ans;
return 0;
}

本来还想更偷懒用long double直接算的,但是在存 20 位数时,long double这个数据类型已经开始有误差了,所以最后一个测试点过不去,可惜了。按理说,long double能存相当大的数了,不应该才 20 位就开始出现误差啊?

1024 Palindromic Number

Analysis

题目大意是给定一个数字,判断是否为回文数字,并进行一系列操作。另外,给定一个上限次数,当给定的数不是回文数字时,令其加上将其逆置后的数字,在进行判断是否为会问数字,若是,则输出这个数字和变换次数,反之,则继续直至超过上限次数。注意,即便超过了上限次数,依然要变换过程中最后的数字。

解决此题需要解决下面3个子问题:

  1. 回文数字的判定
  2. 数字逆置
  3. 数字相加

题目要求数字的范围不超过$10^{10}$,可以使用long long,但这会使得将数字逆置的这个步骤非常麻烦,所以直接使用数组来存储数字,并模拟数字之间的加法。另外这样还有一个好处,就是在判断是否是回文数字时,可以直接对数组进行判断。
使用long long会溢出,直接用字符串就好,别想着偷鸡了。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
#include <iostream>
#include <cstring>
using namespace std;
struct bign {
int d[200], 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 reversebign(bign a) {
int temp;
for(int i = 0; i < a.len / 2; i++) {
temp = a.d[i];
a.d[i] = a.d[a.len - i - 1];
a.d[a.len - i - 1] = temp;
}
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 != 0) {
c.d[c.len++] = carry;
}
return c;
}

bool isPalindromic(bign a) {
for(int i = 0; i <= a.len / 2; i++) {
if(a.d[i] != a.d[a.len - 1 - i]) return false;
}
return true;
}

void print(bign a) {
for(int i = a.len - 1; i >= 0; i--) {
printf("%d", a.d[i]);
}
putchar('\n');
}

int main(int argc, char const *argv[]) {
char str[150];
int times, count = 0;
scanf("%s %d", str, &times);
bign a = change(str), rev;
while(times--) {
if(isPalindromic(a)) {
break;
} else {
rev = reversebign(a);
a = add(a, rev);
count++;
}
}
print(a);
printf("%d", count);
return 0;
}

贴个 C++ 版:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include <iostream>
#include <algorithm>
using namespace std;
bool ispalindromic(string &num) {
int left = 0, right = num.length() - 1;
while(left < right) {
if(num[left] != num[right]) return false;
left++, right--;
}
return true;
}
int main() {
int k;
string num, tmp;
cin >> num >> k;
int i;
reverse(num.begin(), num.end());
for(i = 0; i < k; i++) {
if(ispalindromic(num)) break;
tmp = num;
reverse(tmp.begin(), tmp.end());
int carry = 0;
for(int i = 0; i < num.length(); i++) {
int t = (num[i] + tmp[i] + carry - 2 * '0');
num[i] = t % 10 + '0';
carry = t / 10;
}
if(carry) num.push_back(carry + '0');
}
reverse(num.begin(), num.end());
cout << num << endl;
cout << (i == k ? k : i);
return 0;
}

1025 PTA Ranking

Analysis

此题考察排序,直接调用库里的排序函数来帮助完成排序就好了。注意:

  1. 一个地点内的所有数据输入完了之后,本地排名就可以完成了
  2. 每个数据在在输入的时候就可以顺便对其进行地点编号
  3. 最终排名必须要在本地排名之后才能进行

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

struct student {
char id[15];
int score;
int location_number;
int local_rank;
} stu[30010];

bool cmp(student a, student b);

int main(int argc, char const *argv[]) {
int N, K, num = 0;
scanf("%d", &N);
for(int i = 1; i <= N; i++) {
scanf("%d", &K);
for(int j = 0; j < K; j++) {
scanf("%s %d", stu[num].id, &stu[num].score);
stu[num].location_number = i;
num++;
}
sort(stu + num - K, stu + num, cmp);
stu[num - K].local_rank = 1;
//get local rank
for(int j = num - K + 1; j < num; j++) {
if(stu[j].score == stu[j - 1].score) {
stu[j].local_rank = stu[j - 1].local_rank;
} else {
stu[j].local_rank = j + 1 - (num - K);
}
}
}
printf("%d\n", num);
sort(stu, stu + num, cmp);
//get final rank
int r = 1;
for(int i = 0; i < num; i++) {
if(i > 0 && stu[i].score != stu[i - 1].score) {
r = i + 1;
}
printf("%s ", stu[i].id);
printf("%d %d %d\n", r, stu[i].location_number, stu[i].local_rank);
}
return 0;
}

bool cmp(student a, student b) {
if(a.score != b.score) return a.score > b.score;
else return strcmp(a.id, b.id) < 0;
}

1027 Colors in Mars

Analysis

考察进制转换的题目,10进制转换为13进制,与转换10进制转换为16进制是类似的,代码可能写的不太好看,嘿嘿~

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#include <cstdio>

char Change(int number);
int Transfer(char *dst, int number, int dex);

int main(int argc, char const *argv[]) {
int R, G, B, index = 1;
scanf("%d %d %d", &R, &G, &B);
char color[10] = "#00000000";
index = Transfer(color, R, index);
index = Transfer(color, G, index);
index = Transfer(color, B, index);
color[index] = '\0';
puts(color);
return 0;
}

int Transfer(char *dst, int number, int index) {
int mask = 1, temp = number;
while(temp > 12) {
temp /= 13;
mask *= 13;
}
temp = number;
if(mask > 1) {
while(mask) {
dst[index++] = Change(temp / mask);
temp %= mask;
mask /= 13;
}
} else {
index++;
dst[index++] = Change(temp);
}
return index;
}

char Change(int number) {
char ret;
if(0 <= number && number <= 9) {
ret = number + '0';
} else {
ret = number - 10 + 'A';
}
return ret;
}

贴个 C++ 直接用 map 打表的方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <iostream>
#include <algorithm>
#include <map>
using namespace std;
map<int, string> marscolors;
char num2char(int num) {
char ret = '0';
if(0 <= num && num <= 9) ret += num;
else ret = 'A' + num - 10;
return ret;
}
int main() {
marscolors[0] = "00";
for(int i = 1; i < 169; i++) {
int tmp = i;
string s;
while(tmp) {
s += num2char(tmp % 13);
tmp /= 13;
}
if(i < 13) s += "0";
reverse(s.begin(), s.end());
marscolors[i] = s;
}
int red, green, blue;
cin >> red >> green >> blue;
cout << "#" << marscolors[red] << marscolors[green] << marscolors[blue];
return 0;
}

1028 List Sorting

Analysis

考察排序,用输入的数字表示以元素的某一项进行排序,直接把类别数字用全局变量代替,然后在cmp函数中直接使用即可,注意字符串需要用strcmp函数进行比较。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXN = 100000 + 5;
struct student{
char id[10], name[15];
int grade;
} stu[MAXN];
int N, C;

bool cmp(student a, student b);

int main(int argc, char const *argv[]) {
scanf("%d %d", &N, &C);
for(int i = 0; i < N; i++) {
scanf("%s %s %d", stu[i].id, stu[i].name, &stu[i].grade);
}
sort(stu, stu + N, cmp);
for(int i = 0; i < N; i++) {
printf("%s %s %d\n", stu[i].id, stu[i].name, stu[i].grade);
}
return 0;
}

bool cmp(student a, student b) {
if(C == 1) {
return strcmp(a.id, b.id) < 0;
} else if(C == 2) {
int temp = strcmp(a.name, b.name);
if(temp != 0) return temp < 0;
else return strcmp(a.id, b.id) < 0;
} else {
if(a.grade != b.grade) return a.grade < b.grade;
else return strcmp(a.id, b.id) < 0;
}
}

贴个 C++ 版:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 100000 + 5;
struct student {
string id, name;
int grade;
} stu[maxn];
bool cmp1(student a, student b) {
if(a.name != b.name) return a.name < b.name;
else return a.id < b.id;
}
int n, c;
bool cmp(student a, student b) {
if(c == 1) return a.id < b.id;
else if(c ==2) {
if(a.name != b.name) return a.name < b.name;
else return a.id < b.id;
} else {
if(a.grade != b.grade) return a.grade < b.grade;
else return a.id < b.id;
}
}
int main() {
cin >> n >> c;
for(int i = 0; i < n; i++) {
cin >> stu[i].id >> stu[i].name >> stu[i].grade;
}
sort(stu, stu + n, cmp);
for(int i = 0; i < n; i++) {
cout << stu[i].id << ' ' << stu[i].name << ' ' << stu[i].grade << endl;
}
return 0;
}

1029 Median

Analysis

题目大意是给定两个递增序列,求这两个序列合并后的中位数

明确了什么是中位数之后,解决这个问题的方法就有很多了。超级无脑的做法就是直接把其中一个序列拼接在另外一个序列后面,排个序,然后直接输出其中位数就好了。但是注意到题目的Memory Limit: 1.5 MB,说明题目对内存有要求,简单直接的做法可能导致Memory Limit Exceeded的错误。

那么就需要想办法优化空间了,题目给定的两个序列,按照上述的思路,就需要三个数组(两个存给定的,一个存合并后的),能不能少用一个或两个呢?答案是肯定的,其实可以不用完全合并,而只需要模拟这个合并操作的过程,并在这个过程中,按照顺序来统计是否枚举到了那个中位数(根据数组下标的初始值,中位数的位置是可以直接算出来的)即可。

不过,很可惜,道高一尺魔高一丈,这个题更新(2018年3月之后?)了测试样例,最后一个测试用例还是无法通过,并且还是MLE的错误。

这就得靠在线处理了,在读入第二个序列时,将每次读入的数字存在一个变量内,每次需要统计第一个序列中有多少数字小于它,然后根据这一点来计算出这个数字在合并后的序列中所处的位置,并与中位数的位置进行比较,然后来决定是否输出。在读入第二个序列的过程中存在两种情况:

  1. 数字存在第一个序列内,并且此时可以确定中位数必定比当前读入的数字小
  2. 数字存在第二个序列内,就是当前读入的数字

针对上述两种情况,统计到中位数后直接输出即可,但是要注意,若是第二个序列的数字比第一个序列少很多(或者小很多等极端情况),那么中位数依然还是在第一个序列内,所以还是得在第一个序列内找。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <cstdio>
const int MAXN = 200000 + 10;
int seq[MAXN];
int main(int argc, char const *argv[]) {
int n1, n2, temp, count = 0;
scanf("%d", &n1);
for(int i = 1; i <= n1; i++) {
scanf("%d", &seq[i]);
}
seq[n1 + 1] = 0x7fffffff;
scanf("%d", &n2);
int median = (n1 + n2 + 1) / 2, i = 1;
for(int j = 1; j <= n2; j++) {
scanf("%d", &temp);
while(seq[i] < temp) {
count++;
if(count == median) printf("%d", seq[i]);
i++;
}
count++;
if(count == median) printf("%d", temp);
}
while(i <= n1) {
count++;
if(count == median) printf("%d", seq[i]);
i++;
}
return 0;
}

现在这个题的内存限制已经改成64 MB了,可以直接排序了😂:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;

int main() {
vector<int> arr;
int n, tmp;
cin >> n;
for(int i = 0; i < n; i++) {
cin >> tmp;
arr.push_back(tmp);
}
cin >> n;
for(int i = 0; i < n; i++) {
cin >> tmp;
arr.push_back(tmp);
}
sort(arr.begin(), arr.end());
int pos = arr.size() % 2 == 1 ? arr.size() / 2 : arr.size() / 2 - 1;
cout << arr[pos];
return 0;
}

1030 Travel Plan

Analysis

题目大意是给定一个旅游地图,每个结点之间的边,包含两个属性值:距离和花销。然后,给定起点和终点,要求输出二者之间的最短路径的总距离和对应的花销,若存在相同总距离的最短路径,此时需输出最小的花销值。

由于题目已经说明输入数据不存在负数,且只有一个起点,问题就变成了不存在负环的图的单源最短路径问题所以可以直接使用 Dijkstra 算法进行求解。由于需要输出对应的最短路径,所以可以在 Dijkstra 算法求解最短路径的过程中,顺便利用一个数组来保存最优路径,之后再利用 DFS 来正序输出路径;当然,也可以利用动态数组保存所有的路径,之后再利用 DFS 遍历每条路径,来求解花销值最小的路径。

Code

Dijkstra

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#include <iostream>
#include <cstring>
using namespace std;
const int maxv = 510;
const int inf = 0x3fffffff;
int n, m, s, t, G[maxv][maxv], cost[maxv][maxv];
int d[maxv], c[maxv], pre[maxv];
bool vis[maxv] = {false};
void dijkstra(int s) {
fill(d, d + maxv, inf); // do not forget initialize the distance array
for(int i = 0; i < n; i++) pre[i] = i;
d[s] = 0;
c[s] = 0;
for(int i = 0; i < n; i++) {
int u = -1, min = inf;
for(int j = 0; j < n; j++) {
if(vis[j] == false && d[j] < min) {
u = j;
min = d[j];
}
}
if(u == -1) return;
vis[u] = true;
for(int v = 0; v < n; v++) {
if(vis[v] == false && G[u][v] != inf) {
if(d[u] + G[u][v] < d[v]) {
d[v] = d[u] + G[u][v];
c[v] = c[u] + cost[u][v];
pre[v] = u; // save the precursor
} else if(d[u] + G[u][v] == d[v]) {
if(c[u] + cost[u][v] < c[v]) { // more optimized result
c[v] = c[u] + cost[u][v];
pre[v] = u;
}
}
}
}
}
}
void dfs(int v) {
if(v == s) {
cout << v << ' ';
return;
}
dfs(pre[v]);
cout << v << ' ';
}
int main(int argc, char const *argv[]) {
cin >> n >> m >> s >> t;
fill(G[0], G[0] + maxv * maxv, inf);
int u, v;
for(int i = 0; i < m; i++) {
cin >> u >> v;
cin >> G[u][v] >> cost[u][v];
G[v][u] = G[u][v], cost[v][u] = cost[u][v];
}
dijkstra(s);
dfs(t);
cout << d[t] << ' ' << c[t];
return 0;
}

Dijkstra + DFS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
#include <iostream>
#include <vector>
#include <cstring>
using namespace std;
const int maxv = 510;
const int inf = 0x3fffffff;
int n, m, st, ed, G[maxv][maxv], cost[maxv][maxv];
int d[maxv], mincost = inf; // mincost need to be initialized to 'inf'
bool vis[maxv] = {false};
vector<int> pre[maxv], tempath, path;
void dijkstra(int s) {
fill(d, d + maxv, inf);
d[s] = 0;
for(int i = 0; i < n; i++) {
int u = -1, min = inf;
for(int j = 0; j < n; j++) {
if(vis[j] == false && d[j] < min) {
min = d[j];
u = j;
}
}
if(u == -1) return;
vis[u] = true;
for(int v = 0; v < n; v++) {
if(vis[v] == false && G[u][v] != inf) {
if(d[u] + G[u][v] < d[v]) {
d[v] = d[u] + G[u][v];
pre[v].clear(); // do not forget clear
pre[v].push_back(u);
} else if(d[u] + G[u][v] == d[v]) {
pre[v].push_back(u); // save other shortest path
}
}
}
}
}
void dfs(int v) {
if(v == st) {
tempath.push_back(v);
int tempcost = 0;
for(int i = tempath.size() - 1; i > 0; i--) {
int id = tempath[i], idNext = tempath[i - 1];
tempcost += cost[id][idNext];
}
if(tempcost < mincost) {
path = tempath;
mincost = tempcost;
}
tempath.pop_back();
return;
}
tempath.push_back(v);
for(int i = 0; i < pre[v].size(); i++) {
dfs(pre[v][i]);
}
tempath.pop_back();
}
int main() {
cin >> n >> m >> st >> ed;
fill(G[0], G[0] + maxv * maxv, inf);
int u, v;
for(int i = 0; i < m; i++) {
cin >> u >> v;
cin >> G[u][v] >> cost[u][v];
G[v][u] = G[u][v], cost[v][u] = cost[u][v];
}
dijkstra(st);
dfs(ed);
for(int i = path.size() - 1; i >= 0; i--) {
cout << path[i] << ' ';
}
cout << d[ed] << ' ' << mincost;
return 0;
}

1031 Hello World For U

Analysis

这道题属于打印图形类的题目,题眼大概就是找到图形输出的规律了,所以读题得仔细一点。
不过,很巧地是,这道题目,用来找规律的那个条件不是很明显,可能还不太容易看懂(可能我英语渣~),就是这个条件$n_1 = n_3 = max \lbrace{k | k \le n_2\ for\ all\ 3 \le n_2 \le N}\rbrace \ with \ n_1 + n_2 + n3 - 2 = N$了。意思大致是:$n_1 = n_3 \le k$,而$k$这个数是得严格小于等于$n_2$,而$n_2$的取值范围为:$[3, N]$,另外还有一个条件$n_1 + n_2 + n_3 - 2 = N$。

另外,$n_1$是指最左边一列“字符串”的长度,$n_2$是指底部“字符串”的长度,$n_3$是指最右边一列“字符串”的长度,$N$就是严格意义上的字符串长度了。

事实上,$n_1 = n_3 = (N + 2) / 3$,然后求得$n_2$即可开始打印输出了😒。

可以直接打印输出,不过还要找些小规律(折磨你😆),如第一行输出的是字符串第一个字符和最后一个字符;先输出第一个字符,然后输出空格,接着在输出最后一个字符即可。也可以先把每一个字符放到二维数组内,利用空格初始化二维数组,然后在指定位置放入字符,最后输出即可。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <cstdio>
#include <cstring>

int main(int argc, char const *argv[]) {
int n1, n2, n3, N;
char str[85];
scanf("%s", str);
N = strlen(str);
n1 = n3 = (N + 2) / 3; //get n1 and n3 first
n2 = N + 2 - 2 * n1; //use the condition: n1 + n2 + n3 - 2 = N
for(int i = 0; i < n1; i++) {
if(i == n1 - 1) {
//print the last line
for(int j = i; j <= N - i - 1; j++) {
printf("%c", str[j]);
}
} else {
printf("%c", str[i]);
for(int j = 0; j < n2 - 2; j++) {
putchar(' ');
}
printf("%c", str[N - i - 1]);
}
putchar('\n');
}
return 0;
}

贴个 C++ 版,没有用公式求 n1, n2, n3:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <iostream>
#include <cmath>
using namespace std;

int main() {
string str;
cin >> str;
int n1, n2 = 3, n3, len = str.length();
while(true) {
int diff = len - n2;
if(diff % 2 == 0) {
n1 = n3 = diff / 2;
if(n2 > n1) break;
}
n2++;
}
int i, j;
for(i = 0, j = len - 1; i < n1 && j > len - n3 - 1; i++, j--) {
cout << str[i];
for(int k = 0; k < n2 - 2; k++) cout << ' ';
cout << str[j] << endl;
}
while(i <= j) cout << str[i++];
return 0;
}

1032 Sharing

Analysis

题目大意是使用链表存储英文字符时,因为英文字符存在相同的后缀,所以公共后缀只存储一次,然后让不同且具有这个公共后缀单词的最后一个不属于这个后缀的字母的next指向公共后缀的第一个字母即可,这样就可以节约一定的存储空间了。

按照题目背景,题目要求找出具有两个单词的公共后缀的第一个字母的地址并输出,若不存在,则输出-1。直观的做法是,遍历第一个链表,同时遍历第二个链表,找到二者中具有相同address的元素,输出即可,此时的时间复杂度为:$O(n^2)$。

按照题目给定的形式,使用静态链表来处理问题,接着上面的思考,若在遍历第一个链表时,给其每一个结点都加上一个标志位;接着在遍历第二个链表时,就可以直接判断第二个链表的结点的标志位是否与第一个链表结点的标志位相同,若相同,则这个结点就是二者公共后缀的第一个字母了,就可以输出了,这样时间复杂度就降为:$O(n)$了。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <cstdio>
#include <cstring>
const int maxn = 100010;

struct Node{
char data;
int next;
bool flag;
} node[maxn];

int main(int argc, char const *argv[]) {
for(int i = 0; i < maxn; i++) {
node[i].flag = false;
}
int head1, head2, n;
scanf("%d %d %d", &head1, &head2, &n);
int address, next;
char data;
for(int i = 0; i < n; i++) {
scanf("%d %c %d", &address, &data, &next);
node[address].next = next;
node[address].data = data;
}
int p;
for(p = head1; p != -1; p = node[p].next) {
node[p].flag = true;
}
for(p = head2; p != -1; p = node[p].next) {
if(node[p].flag == true) break;
}
if(p != -1) {
printf("%05d\n", p);
} else {
printf("-1\n");
}
return 0;
}

1033 To Fill or Not to Fill

Analysis

此题考察贪心算法,如何进行“贪心”得从结果和题意上去分析。

依据结果,每次经过一个加油站时,需要将当前加油站与小车从当前加油站能到达的每个加油站的油价进行比较,若存在油价更低的加油站,那么就加刚好能到达那个加油站的油量,否则就加满。所以需要将加油站按照离杭州的距离从小到大进行排列,并假设目的地离杭州的距离为输入距离,油价为0(这样做的目的是为了方便比较,不用处理特殊情况)。然后,开始模拟小车从起点出发。

当第一个加油站离杭州的距离不为0时,说明小车无法出城,直接输出The maximum travel distance = 0.00即可。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#include <cstdio>
#include <algorithm>
using namespace std;
const int MAXN = 500 + 5;
const int INF = 1000000000;
struct station {
double price, dis;
} sta[MAXN];
bool cmp(station a, station b);

int main(int argc, char const *argv[]) {
double cmax, d, davg;
int N;
scanf("%lf %lf %lf %d", &cmax, &d, &davg, &N);
for(int i = 0; i < N; i++) {
scanf("%lf %lf", &sta[i].price, &sta[i].dis);
}
sta[N].price = 0;
sta[N].dis = d;
sort(sta, sta + N, cmp);
if(sta[0].dis != 0) {
printf("The maximum travel distance = 0.00\n");
} else {
int now = 0;
double ans = 0, capacity = 0, max = cmax * davg;
while(now < N) {
int k = -1;
double priceMin = INF;
for(int i = now + 1; i <= N && sta[i].dis - sta[now].dis <= max; i++) {
if(sta[i].price < priceMin) {
priceMin = sta[i].price;
k = i;
if(priceMin < sta[now].price) {
break;
}
}
}
if(k == -1) break;
double need = (sta[k].dis - sta[now].dis) / davg;
if(priceMin < sta[now].price) {
if(capacity < need) {
ans += (need - capacity) * sta[now].price;
capacity = 0;
} else {
capacity -= need;
}
} else {
ans += (cmax - capacity) * sta[now].price;
capacity = cmax - need;
}
now = k;
}
if(now == N) {
printf("%.2lf\n", ans);
} else {
printf("The maximum travel distance = %.2lf\n", sta[now].dis + max);
}
}
return 0;
}

bool cmp(station a, station b) {
return a.dis < b.dis;
}

重新写了一下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include <cstdio>
#include <cfloat>
#include <algorithm>
using namespace std;
const int maxn = 500 + 5;
struct station {
double price, dis;
} sta[maxn];

int main() {
double cmax, d, davg;
int n;
scanf("%lf %lf %lf %d", &cmax, &d, &davg, &n);
for(int i = 0; i < n; i++) {
scanf("%lf %lf", &sta[i].price, &sta[i].dis);
}
sta[n].dis = d, sta[n].price = 0;
sort(sta, sta + n, [&](station a, station b) { return a.dis < b.dis; });
if(sta[0].dis != 0) {
printf("The maximum travel distance = 0.00\n");
} else {
int now = 0;
double ans = 0, tank = 0, max = cmax * davg;
while(now < n) {
int k = -1;
double minprice = DBL_MAX;
for(int i = now + 1; i <= n && sta[i].dis - sta[now].dis <= max; i++) {
if(sta[i].price < minprice) {
minprice = sta[i].price;
k = i;
if(minprice < sta[now].price) break;
}
}
if(k == -1) break;
double need = (sta[k].dis - sta[now].dis) / davg;
if(minprice < sta[now].price) {
if(tank < need) {
ans += (need - tank) * sta[now].price;
tank = 0;
} else tank -= need;
} else {
ans += (cmax - tank) * sta[now].price;
tank = cmax - need;
}
now = k;
}
if(now == n) printf("%.2lf\n", ans);
else printf("The maximum travel distance = %.2lf\n", sta[now].dis + max);
}
return 0;
}

1034 Head of a Gang

Analysis

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
#include <iostream>
#include <string>
#include <map>
using namespace std;
const int maxn = 2010;
const int INF = 1000000000;

map<int, string> intTostring;
map<string, int> stringToint;
map<string, int> Gang;
int G[maxn][maxn] = {0}, weight[maxn] = {0};
int n, k, numPerson = 0;
bool visited[maxn] = {false};
void DFS(int nowVisit, int &head, int &numMember, int &totalValue) {
numMember++;
visited[nowVisit] = true;
if(weight[nowVisit] > weight[head]) {
head = nowVisit;
}
for(int i = 0; i < numPerson; i++) {
if(G[nowVisit][i] > 0) {
totalValue += G[nowVisit][i];
G[nowVisit][i] = G[i][nowVisit] = 0;
if(visited[i] == false) {
DFS(i, head, numMember, totalValue);
}
}
}
}
void DFSTrave() {
for(int i = 0; i < numPerson; i++) {
if(visited[i] == false) {
int head = i, numMember = 0, totalValue = 0;
DFS(i, head, numMember, totalValue);
if(numMember > 2 && totalValue > k) {
Gang[intTostring[head]] = numMember;
}
}
}
}
int change(string s) {
if(stringToint.find(s) != stringToint.end()) {
return stringToint[s];
} else {
stringToint[s] = numPerson;
intTostring[numPerson] = s;
return numPerson++;
}
}
int main(int argc, char const *argv[]) {
int w;
string s1, s2;
cin >> n >> k;
for(int i = 0; i < n; i++) {
cin >> s1 >> s2 >> w;
int id1 = change(s1);
int id2 = change(s2);
weight[id1] += w;
weight[id2] += w;
G[id1][id2] += w;
G[id2][id1] += w;
}
DFSTrave();
cout << Gang.size() << endl;
map<string, int>::iterator it;
for(it = Gang.begin(); it != Gang.end(); it++) {
cout << it->first << ' ' << it->second << endl;
}
return 0;
}

1035 Password

Analysis

题目看着臭长臭长的,其实比较简单,就是有些小小的细节...

先分析输入格式,给个N代表N组数据,然后每一组数组按照name password的格式来给出,都是字符串,由于输出时后要同等输出,所以方便起见定义一个结构体来保存这些数据;再者,由于最后得先输出被修改的数量,所以得先把数据都存储下来,才能在输出数量后,在输出修改的信息。

再看输出格式,若有修改,就输出修改的数量,然后每行紧接着每个结构体内的信息;若没有修改,就输出There are N accounts and no account is modified,注意这里的细节,当N1时,得输出There is 1 account and no account is modified,这两句英文在N1和其他数时使用的Be动词不一样(老师出题很严谨的,🤣英语要学好,哈哈~)。

其他就没什么了。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#include <cstdio>
const int MAXN = 1000 + 5;
struct info {
char name[12], password[12];
int flag;
} Info[MAXN];

int main(int argc, char const *argv[]) {
int N, count = 0;
scanf("%d", &N);
for(int i = 0; i < N; i++) {
scanf("%s %s", Info[i].name, Info[i].password);
char *p = Info[i].password;
while(*p != '\0') {
if(*p == '1') {
*p = '@';
Info[i].flag = 5;
} else if(*p == '0') {
*p = '%';
Info[i].flag = 5;
} else if(*p == 'l') {
*p = 'L';
Info[i].flag = 5;
} else if(*p == 'O') {
*p = 'o';
Info[i].flag = 5;
}
p++;
}
if(Info[i].flag != 5) {
count++;
}
}
if(count == N) {
if(count == 1) printf("There is %d account and no account is modified\n", count);
else printf("There are %d accounts and no account is modified", count);
} else {
printf("%d\n", N - count);
for(int i = 0; i < N; i++) {
if(Info[i].flag == 5) {
printf("%s %s\n", Info[i].name, Info[i].password);
}
}
}
return 0;
}

贴个 C++ 版本的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <iostream>
#include <vector>
using namespace std;

int main() {
int m, cnt = 0;
cin >> m;
string account, password;
vector<vector<string>> ans;
for(int i = 0; i < m; i++) {
cin >> account >> password;
bool flag = false;
for(int j = 0; j < password.length(); j++) {
switch(password[j]) {
case '1': password[j] = '@'; flag = true; break;
case '0': password[j] = '%'; flag = true; break;
case 'l': password[j] = 'L'; flag = true; break;
case 'O': password[j] = 'o'; flag = true; break;
default: break;
}
}
if(flag) {
ans.push_back({account, password});
cnt++;
}
}
if(!cnt) {
if(m <= 1) cout << "There is " << m << " account";
else cout << "There are " << m << " accounts";
cout << " and no account is modified";
} else {
cout << cnt << endl;
for(int i = 0; i < ans.size(); i++) {
cout << ans[i][0] << ' ' << ans[i][1] << endl;
}
}
return 0;
}

太麻烦了,这个题...

1036 Boys vs Girls

Analysis

题目意思很简单,找出女生中分最高的,男生中分最低的,分别输出他们的姓名、学号和分数之差即可,由于最后需要的两个结果可能没有出现,利用两个标记来记录状态,然后根据4种不同的状态,分别对应输出即可。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#include <cstdio>

struct student{
char name[15];
char id[15];
char gender;
int grade;
} Fhighest, Mlowest, temp;

void Init();
bool Highest(student a, student b);
bool Lowest(student a, student b);

int main(int argc, char const *argv[]) {
Init();
int N;
bool Fflag = false, Mflag = false;
scanf("%d", &N);
while(N--) {
scanf("%s %c %s %d", temp.name, &temp.gender, temp.id, &temp.grade);
if(temp.gender == 'F') {
if(Highest(temp, Fhighest)) {
Fhighest = temp;
Fflag = true;
}
} else if(temp.gender == 'M') {
if(Lowest(temp, Mlowest)) {
Mlowest = temp;
Mflag = true;
}
}
}
if(!Fflag && !Mflag) {
printf("Absent\nAbsent\nNA\n");
} else if(Fflag && !Mflag) {
printf("%s %s\nAbsent\nNA\n", Fhighest.name, Fhighest.id);
} else if(!Fflag && Mflag) {
printf("Absent\n%s %s\nNA\n", Mlowest.name, Mlowest.id);
} else {
printf("%s %s\n%s %s\n%d\n", Fhighest.name, Fhighest.id, Mlowest.name, Mlowest.id, Fhighest.grade - Mlowest.grade);
}
return 0;
}

void Init() {
Fhighest.grade = -1;
Mlowest.grade = 100;
}

bool Highest(student a, student b) {
return a.grade >= b.grade;
}
bool Lowest(student a, student b) {
return a.grade <= b.grade;
}

贴个 C++ 版:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include <iostream>
using namespace std;

int main() {
int n;
cin >> n;
string malename, femalename, maleid, femaleid, name, clas, maleclass, femaleclass;
char gender;
int grade, highest = -1, lowest = 101;
while(n--) {
cin >> name >> gender >> clas >> grade;
if(gender == 'M') {
if(grade < lowest) {
lowest = grade;
malename = name;
maleclass = clas;
}
}
if(gender == 'F') {
if(grade > highest) {
highest = grade;
femalename = name;
femaleclass = clas;
}
}
}
if(highest < 0) cout << "Absent\n";
else cout << femalename << ' ' << femaleclass << endl;
if(lowest > 100) cout << "Absent\n";
else cout << malename << ' ' << maleclass << endl;
if(lowest > 100 || highest < 0) cout << "NA\n";
else cout << highest - lowest;
return 0;
}

1037 Magic Coupon

Analysis

这道题考察贪心算法,题目要求输出可以得到的最大钱数。注意这段话:print in a line the maximum amount of money you can get back的表述,所以只需要得到能得到的最大值就可以了,不需要统计负数的情况所以只需要统计收钱的情况,付钱的情况不用统计了。
若只统计一张券乘以一件商品价格的结果为正数的情况,就分为两种:

  1. 券值为正,商品价格为正,面值最大的券需要乘以价格最高的商品,就能得到最大的结果。
  2. 券值为负,商品价格为负,面值最小(负数)的券需要乘以价格最低(负数)的商品,就能得到最大的结果。

利用两个数组来分别存储券值和商品价格,按照大小排序后,开始相乘,计算最终结果。注意,升序和降序不影响结果,但需要两种情况需要分开处理。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <cstdio>
#include <algorithm>
using namespace std;
const int MAXN = 100000 + 5;

int main(int argc, char const *argv[]) {
int Nc, Np, coupon[MAXN] = {0}, product[MAXN] = {0};
scanf("%d", &Nc);
for(int i = 0; i < Nc; i++) {
scanf("%d", &coupon[i]);
}
scanf("%d", &Np);
for(int i = 0; i < Np; i++) {
scanf("%d", &product[i]);
}
sort(coupon, coupon + Nc);
sort(product, product + Np);
int i = 0, j, ans = 0;
while(i < Nc && i < Np && coupon[i] < 0 && product[i] < 0) {
ans += coupon[i] * product[i];
i++;
}
i = Nc - 1;
j = Np - 1;
while(i >= 0 && j >= 0 && coupon[i] > 0 && product[j] > 0) {
ans += coupon[i] * product[j];
i--, j--;
}
printf("%d\n", ans);
return 0;
}

贴个 C++ 版:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <iostream>
#include <queue>
using namespace std;
priority_queue<int, vector<int>, greater<int>> c1, p1;
priority_queue<int, vector<int>, less<int>> c2, p2;
int main() {
int nc, np, tmp;
cin >> nc;
for(int i = 0; i < nc; i++) {
cin >> tmp;
if(tmp < 0) c1.push(tmp);
if(tmp > 0) c2.push(tmp);
}
cin >> np;
for(int i = 0; i < np; i++) {
cin >> tmp;
if(tmp < 0) p1.push(tmp);
if(tmp > 0) p2.push(tmp);
}
long long ans = 0;
while(!c1.empty() && !p1.empty()) {
int ctmp = c1.top(); c1.pop();
int ptmp = p1.top(); p1.pop();
ans += ctmp * ptmp;
}
while(!c2.empty() && !p2.empty()) {
int ctmp = c2.top(); c2.pop();
int ptmp = p2.top(); p2.pop();
ans += ctmp * ptmp;
}
cout << ans;
return 0;
}

粗略分析一下,堆的时间复杂度应该优于排序,同样需要 $O(n)$ 的存储空间,不过极端情况下,二者应该差不多。另外,其实可以在最后的结果ans这里挖坑,故意弄成溢出的情况,因为题目只说了保证给的数组不超过 $2^{30}$。

1038 Recover the Smallest Number

Analysis

题目会给一些数字,要求将给定的所有数字“拼接”起来,最终得到一个组合数,这个数字要比按照其他方式组合得到的结果小。

由于不能打乱给定的每个数字的数位顺序,所以一般会想到直接按照字典序比较每个数字的大小,然后让小的的在前面,大的在后面。但要注意,如果数字32, 321,按字典序大小排列后的组合数是32321,此时存在更小的结果32132,所以不能单纯的按照这种思路进行。

对于32, 321这两个数字而言,按照上面的结果:32132 < 32321,从字符串的角度出发,假设a = 32, b = 321,则有ba < ab,这样就可以在两个数中找出“拼接”出的最小数了。按照这种思路,对每一个数字(以字符串形式存储)都这样排序,最后逐个输出的结果就是题目要求的最小数字了。

确定要用字符串了后,直接使用STL内的string类可以很方便的对字符串进行操作。

注意,当输入的全部为0时,需要特判输出0

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
const int MAXN = 10000 + 10;
string str[MAXN];
bool cmp(string a, string b);

int main(int argc, char const *argv[]) {
int n;
cin >> n;
for(int i = 0; i < n; i++) {
cin >> str[i];
}
sort(str, str + n, cmp);
string ans;
for(int i = 0; i < n; i++) {
ans += str[i];
}
while(ans.size() != 0 && ans[0] == '0') {
ans.erase(ans.begin());
}
if(ans.size() == 0) {
cout << 0;
} else {
cout << ans;
}
return 0;
}

bool cmp(string a, string b) {
return a + b < b + a;
}

又写了一遍:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int main() {
vector<string> strs;
int n;
cin >> n;
for(int i = 0; i < n ; i++) {
string tmp;
cin >> tmp;
strs.push_back(tmp);
}
sort(strs.begin(), strs.end(), [](string &a, string &b) {
return a + b < b + a;
});
string ans;
for(int i = 0; i < n; i++) {
ans += strs[i];
}
while(ans.length() != 0 && *ans.begin() == '0') {
ans.erase(ans.begin());
}
if(ans.length() == 0) cout << "0";
else cout << ans;
return 0;
}

这个题的贪心策略就是局部最优,然后达到的全局最优。

1039 Course List for Student

Analysis

题目大意是给定课程数目和每门课程参加的学生姓名,当用学生姓名查找时,输出该名学生所有的课程。

根据题目要求,需要保存每名学生的选课信息,课程都是用数字代替的,所以使用数组就可以满足需求。由于需要按序输出每名学生的课程编号,所以需要对每名学生的课程编号进行排序;并且,还需要先输出该名学生选课的总数。综合考虑后,使用vector来保存数据比较合适。另外为了便于查找,采用散列的思想,将学生的姓名转换为数字,作为下标来保存数据。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
const int N = 40010;
const int M = 26 * 26 * 26 * 10 + 1;
vector<int> selectCourse[M];

int getID(char *name) {
int id = 0;
for(int i = 0; i < 3; i++) {
id = id * 26 + (name[i] - 'A');
}
id = id * 10 + (name[3] - '0');
return id;
}

int main(int argc, char const *argv[]) {
char name[5];
int n, k;
scanf("%d %d", &n, &k);
for(int i = 0; i < k; i++) {
int course, x;
scanf("%d %d", &course, &x);
for(int j = 0; j < x; j++) {
scanf("%s", name);
int id = getID(name);
selectCourse[id].push_back(course);
}
}
for(int i = 0; i < n; i++){
scanf("%s", name);
int id = getID(name);
sort(selectCourse[id].begin(), selectCourse[id].end());
printf("%s %d", name, selectCourse[id].size());
for(int j = 0; j < selectCourse[id].size(); j++) {
printf(" %d", selectCourse[id][j]);
}
putchar('\n');
}
return 0;
}

现在时间限制放宽到了600ms,所以可以放心大胆的用 map、cin 和 cout 了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <iostream>
#include <unordered_map>
#include <algorithm>
#include <vector>
using namespace std;
unordered_map<string, vector<int>> stu;

int main() {
int n, k;
cin >> n >> k;
string name;
while(k--) {
int cid, amount;
cin >> cid >> amount;
for(int i = 0; i < amount; i++) {
cin >> name;
stu[name].push_back(cid);
}
}
while(n--) {
cin >> name;
cout << name << ' ' << stu[name].size();
sort(stu[name].begin(), stu[name].end());
for(int &i: stu[name]) {
cout << ' ' << i;
}
cout << endl;
}
return 0;
}

1040 Longest Symmetric String

Analysis

题目大意是给定一个字符串,找出其中的最长回文子串。
此题并没有设置超时测试点,直接使用暴力解法可以过。不过,这类最长公共子串(Longest Palindromic Substring)的题目,还有另外一种思路——动态规划。

Code

Violent Solution

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <cstdio>
#include <cstring>
const int maxn = 1010;
bool palindrome(char *s1, char *s2) {
bool flag = true;
for(; s1 < s2; s1++, s2--) {
if(*s1 != *s2) {
flag = false;
break;
}
}
return flag;
}
int main(int argc, char const *argv[]) {
char str[maxn];
fgets(str, maxn, stdin);
char *p1, *p2;
int max_len = 0, temp;
for(p1 = str; *p1 != '\0'; p1++) {
for(p2 = p1 + 1; *p2 != '\0'; p2++) {
if(*p1 == *p2) {
temp = p2 - p1;
if(temp <= max_len) continue;
else if(palindrome(p1, p2)) max_len = temp;
}
}
}
printf("%d", max_len + 1);
return 0;
}

DP

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <cstdio>
#include <cstring>
const int maxn = 1010;
char str[maxn];
int dp[maxn][maxn];
int main(int argc, char const *argv[]) {
fgets(str, maxn, stdin);
int len = strlen(str), ans = 1;
memset(dp, 0, sizeof(dp));
for(int i = 0; i < len; i++) {
dp[i][i] = 1;
if(i < len - 1) {
if(str[i] == str[i + 1]) {
dp[i][i + 1] = 1;
ans = 2;
}
}
}
for(int l = 3; l <= len; l++) {
for(int i = 0; i + l - 1 < len; i++) {
int j = i + l - 1;
if(str[i] == str[j] && dp[i + 1][j - 1] == 1) {
dp[i][j] = 1;
ans = l;
}
}
}
printf("%d", ans);
return 0;
}

1041 Be Unique

Analysis

根据题目要求,最先猜到只出现一次的数字就赢了,所以得先按照顺序读入每个数,同时统计每个数字的出现次数。然后再按照输入顺序,检查每个数字的出现次数,若出现一次即为赢的那个数字。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <cstdio>
const int MAXN = 100000 + 5;

int main(int argc, char const *argv[]) {
int N, Num[MAXN] = {0}, times[MAXN] = {0};
scanf("%d", &N);
for(int i = 0; i < N; i++) {
scanf("%d", &Num[i]);
times[Num[i]]++;
}
int i;
for(i = 0; i < N; i++) {
if(times[Num[i]] == 1) {
printf("%d", Num[i]);
break;
}
}
if(i == N) {
printf("None");
}
return 0;
}

1042 Shuffling Machine

Analysis

根据题目的例子,读懂题目,注意仅在一个数组内交换元素会 WA ,要用两个数组进行倒换才能得到正确的结果。当然,也可以在每次倒换完成之后,将得到的序列直接放到结果数组中,这样就不用在判断了。

需要输出的字符串可以先写个循环输出,然后从黑框框中复制粘贴要初始化的二维数组中。如果不想这么干也可以只保存符号信息,也就是

1
char cards[6] = "SHCDJ";

这样,数组中数字跟卡片类型下标的对应关系就是index = (arr[i] - 1) % 13,那序号呢?实际上也是差不多的,也就是(arr[i] - 1) % 13 + 1,所以就可以得到第二个版本的代码。

Code

version 1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include <iostream>
using namespace std;
char playcards[55][5] = {
" ",
"S1", "S2", "S3", "S4", "S5", "S6", "S7", "S8", "S9", "S10", "S11", "S12", "S13",
"H1", "H2", "H3", "H4", "H5", "H6", "H7", "H8", "H9", "H10", "H11", "H12", "H13",
"C1", "C2", "C3", "C4", "C5", "C6", "C7", "C8", "C9", "C10", "C11", "C12", "C13",
"D1", "D2", "D3", "D4", "D5", "D6", "D7", "D8", "D9", "D10", "D11", "D12", "D13",
"J1", "J2",
};
int main() {
int k, arr[55], brr[55], order[55], flag = 1;
cin >> k;
for(int i = 1; i <= 54; i++) {
cin >> order[i];
brr[i] = i;
}
while(k--) {
if(flag) {
for(int i = 1; i <= 54; i++) {
arr[order[i]] = brr[i];
}
flag = 0;
} else {
for(int i = 1; i <= 54; i++) {
brr[order[i]] = arr[i];
}
flag = 1;
}
}
if(!flag) {
for(int i = 1; i <= 54; i++) {
cout << playcards[arr[i]];
if(i != 54) cout << ' ';
}
} else {
for(int i = 1; i <= 54; i++) {
cout << playcards[brr[i]];
if(i != 54) cout << ' ';
}
}
return 0;
}

version 2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <cstdio>
int k, shuffle[55], tmp1[55], tmp2[55];
char cards[5] = {'S', 'H', 'C', 'D', 'J'};

int main() {
scanf("%d", &k);
for(int i = 1; i <= 54; i++) {
scanf("%d", &shuffle[i]);
tmp2[i] = i;
}
for(int i = 1; i <= k; i++) {
for(int i = 1; i <= 54; i++) {
tmp1[shuffle[i]] = tmp2[i];
}
for(int i = 1; i <= 54; i++) {
tmp2[i] = tmp1[i];
}
}
for(int i = 1; i <= 54; i++) {
printf("%c%d", cards[(tmp1[i] - 1) / 13] , (tmp1[i] - 1) % 13 + 1);
if(i != 54) printf(" ");
}
return 0;
}

1043 Is It a Binary Search Tree

Analysis

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
#include <iostream>
#include <vector>
using namespace std;
struct node {
int data;
node *left, *right;
};

void insert(node *&root, int data) {
if(root == NULL) {
root = new node;
root->data = data;
root->left = root->right = NULL;
return;
}
if(data < root->data) insert(root->left, data);
else insert(root->right, data);
}
void preorder(node *root, vector<int> &vi) {
if(root == NULL) return;
vi.push_back(root->data);
preorder(root->left, vi);
preorder(root->right, vi);
}
void preordermirror(node *root, vector<int> &vi) {
if(root == NULL) return;
vi.push_back(root->data);
preordermirror(root->right, vi);
preordermirror(root->left, vi);
}
void postorder(node *root, vector<int> &vi) {
if(root == NULL) return;
postorder(root->left, vi);
postorder(root->right, vi);
vi.push_back(root->data);
}
void postordermirror(node *root, vector<int> &vi) {
if(root == NULL) return;
postordermirror(root->right, vi);
postordermirror(root->left, vi);
vi.push_back(root->data);
}

vector<int> origin, pre, preM, post, postM;
int main(int argc, char const *argv[]) {
int n, data;
node *root = NULL;
scanf("%d", &n);
for(int i = 0; i < n; i++) {
scanf("%d", &data);
origin.push_back(data);
insert(root, data);
}
preorder(root, pre);
preordermirror(root, preM);
postorder(root, post);
postordermirror(root, postM);
if(origin == pre) {
cout << "YES\n";
for(int i = 0; i < post.size(); i++) {
cout << post[i];
if(i < post.size() - 1) cout << ' ';
}
} else if(origin == preM) {
cout << "YES\n";
for(int i = 0; i < postM.size(); i++) {
cout << postM[i];
if(i < postM.size() - 1) cout << ' ';
}
} else {
cout << "NO\n";
}
return 0;
}

1044 Shopping in Mars

Analysis

先分析题目输入,第一行给定两个数字,第一个数字代表一条“链”上钻石的数量,第二个数字则代表需要支付的钱;第二行依次给出“链”上每颗钻石的对应的价值(用于支付)。

然后,题目要求从这条“链”中找出能刚好用于支付(钻石的价值和与待支付的钱相等)的“钻石序列”,当然,若是没有完全相等的情况,找出刚好大于待支付的钱的钻石序列,也是可以的。

将本体的题意抽象出来就是,给定一个序列,找出这个序列中连续子序列和刚好大于或等于给定数字的所有子序列(如果有相等的情况,就不需要再找大于的情况)。

按照这样的思路,可以使用一个sum数组来保存连续的子序列和(每次累加即可),这样在ij之间的子序列和就是sum[j] - sum[i - 1],这个思想与 1046 是一致的。这样,要做的事情就是从sum这个数组中找出满足条件的序列了。同时注意到,由于sum数组是累加得出的,所以一定是严格递增的,也就可以使用二分查找来找这个值。

注意题目的条件:It is guaranteed that the total value of diamonds is sufficient to pay the given amount.,说明肯定会有解,那么对应的也就只有两种情况:

  1. 能找到相等的序列,此时由于序列本身就是严格递增的
  2. 只能找到刚好大于给定值的序列,此时需要用一个变量nearS来保存刚好大于给定值的连续子序列和

找到合理的值后,按照这个值输出即可。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#include <cstdio>
const int MAXN = 100000 + 10;
int sum[MAXN];
int n, S, nearS = 100000000 + 10;

int UpperBound(int L, int R, int x);

int main(int argc, char const *argv[]) {
scanf("%d %d", &n, &S);
sum[0] = 0;
for(int i = 1; i <= n; i++) {
scanf("%d", &sum[i]);
sum[i] += sum[i - 1];
}
for(int i = 1; i <= n; i++) {
int j = UpperBound(i, n + 1, sum[i - 1] + S);
if(sum[j - 1] - sum[i - 1] == S) {
nearS = S;
break;
} else if(j <= n && sum[j] - sum[i - 1] < nearS) {
nearS = sum[j] - sum[i - 1];
}
}
for(int i = 1; i <= n; i++) {
int j = UpperBound(i, n + 1, sum[i - 1] + nearS);
if(sum[j - 1] - sum[i - 1] == nearS) {
printf("%d-%d\n", i, j - 1);
}
}
return 0;
}

int UpperBound(int L, int R, int x) {
int left = L, right = R, mid;
while(left < right) {
mid = (left + right) / 2;
if(sum[mid] > x) {
right = mid;
} else {
left = mid + 1;
}
}
return left;
}

原来使用二分 + 前缀和的思路做的,现在又写了一下,思路是滑动窗口 + 前缀和:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
vector<pair<int, int>> ans1, ans2;
const int maxn = 100000 + 5;
int arr[maxn];
long long prefixsum[maxn];

int main() {
int n, m;
cin >> n >> m;
prefixsum[1] = 0;
for(int i = 1; i <= n; i++) {
cin >> arr[i];
prefixsum[i + 1] = prefixsum[i] + arr[i];
}
int left = 1, right = 2, minimum = 1000;
while(left <= n) {
while(right <= n + 1) {
if(prefixsum[right] - prefixsum[left] < m) right++;
else if(prefixsum[right] - prefixsum[left] == m) {
if(right > left) ans1.push_back({left, right - 1});
else if(right == left) ans1.push_back({left - 1, right - 1});
break;
} else if(prefixsum[right] - prefixsum[left] > m) {
int tmp = prefixsum[right] - prefixsum[left] - m;
if(tmp < minimum) {
ans2.clear();
minimum = tmp;
if(right > left) ans2.push_back({left, right - 1});
else if(right == left) ans2.push_back({left - 1, right - 1});
} else if(tmp == minimum) {
if(right > left) ans2.push_back({left, right - 1});
else if(right == left) ans2.push_back({left - 1, right - 1});
}
break;
}
}
left++;
}
if(ans1.size() != 0) {
sort(ans1.begin(), ans1.end());
for(auto p: ans1) {
cout << p.first << '-' << p.second << endl;
}
} else {
sort(ans2.begin(), ans2.end());
for(auto p: ans2) {
cout << p.first << '-' << p.second << endl;
}
}
return 0;
}

这个题的测试用例中没有 0 的存在...弱了不少

1045 Favorite Color Stripe

Analysis

题目大意:用不同的数字表示不同的颜色,一共有 220 种颜色,给定一串数字序列,作为 Eva 喜欢的颜色种类(越靠后越喜欢),然后在给定一串数字序列。现在从中挑出 Eva 喜欢的所有数字,并且要求按照给定的顺序进行排列,求出这个最大的长度。

如果直接使用暴力解法,定会超时,要想完美解决这个问题,思考的方向有两个,但都包含了动态规划(Dynamic Programming)的思想:

  1. 从最长非递减序列的角度思考
  2. 从最长公共子串的角度思考

Code

LIS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <iostream>
#include <cstring>
using namespace std;
const int maxc = 210;
const int maxn = 10010;
int stripe[maxn], hashTable[maxc], dp[maxn];
int main(int argc, char const *argv[]) {
int n, m, x;
cin >> n >> m;
memset(hashTable, -1, sizeof(hashTable));
for(int i = 0; i < m; i++) {
cin >> x;
hashTable[x] = i;
}
int l, num = 0;
cin >> l;
for(int i = 0; i < l; i++) {
cin >> x;
stripe[num++] = hashTable[x];
}
int ans = -1;
for(int i = 0; i < num; i++) {
dp[i] = 1;
for(int j = 0; j < i; j++) {
if(stripe[j] <= stripe[i] && dp[i] < dp[j] + 1) {
dp[i] = dp[j] + 1;
}
}
ans = max(ans, dp[i]);
}
cout << ans;
return 0;
}

LCS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <iostream>
#include <cstring>
using namespace std;
const int maxc = 210;
const int maxn = 10010;
int A[maxc], B[maxn], dp[maxc][maxn];
int main(int argc, char const *argv[]) {
int n, m;
cin >> n >> m;
for(int i = 1; i <= m; i++) {
cin >> A[i];
}
int l;
cin >> l;
for(int i = 1; i <= l; i++) {
cin >> B[i];
}
for(int i = 1; i <= m; i++) {
dp[i][0] = 0;
}
for(int j = 1; j <= l; j++) {
dp[0][j] = 0;
}
for(int i = 1; i <= m; i++) {
for(int j = 1; j <= l; j++) {
int Max = max(dp[i - 1][j], dp[i][j - 1]);
if(A[i] == B[j]) {
dp[i][j] = Max + 1;
} else {
dp[i][j] = Max;
}
}
}
cout << dp[m][l];
return 0;
}

1046 Shortest Distance

Analysis

题目意思很明确,给你一个“环”形地图,问你从这里到那里怎么走最近。根据题目意思,一般都有两种走法,一种顺着环走,一种逆着环走,找出二者的最小值即可。

一般而言,我们分别找出其中两次的值,进行比较后输出最小值即可。不过由于地名是按照数字给出的,可能会出现起始点的数字大于终点的情况,此时最好交换二者的值,或者分情况讨论。

另外,还可以发现,如果求出了一种走法,那么按照环形地图的特点,利用总距离减去求得的不就得到另一种走法的距离了吗?

把握住上面的点后,可以通过 0 和 1 两个测试点了,第三个测试点会因为超时无法通过。

在仔细分析一下,如果一开始用一个数组Dis[MAXN],按照顺序表示1号地点到达其他地点的距离,那么对于每一次查询的startend,其距离就是Dis[end - 1] - Dis[start - 1]。以样例为例,可以得到数组(下标从1开始)Dis[6] = {0, 1, 3, 7, 21, 30},此时如果要计算52的距离,根据思路就是:Dis[5 - 1] - Dist[2 - 1] = 21 - 1 = 20,这就是按顺序方向从25的距离。

此法恐怖之极在于原本时间复杂度为 $O(n)$ 的查找一下子就变为 $O(1)$ 了。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <cstdio>
#include <algorithm>
using namespace std;
const int MAXN = 100000 + 5;

int main(int argc, char const *argv[]) {
int M, N, Exits[MAXN] = {0}, Dis[MAXN], Sum_D = 0, src, dst;
scanf("%d", &N);
for(int i = 1; i <= N; i++) {
scanf("%d", &Exits[i]);
Sum_D += Exits[i];
Dis[i] = Sum_D;
}
scanf("%d", &M);
while(M--) {
scanf("%d %d", &src, &dst);
if(src > dst) {
swap(src, dst);
}
int temp = Dis[dst - 1] - Dis[src - 1];
printf("%d\n", temp < (Sum_D - temp) ? temp : (Sum_D - temp));
}
return 0;
}

1047 Student List for Course

Analysis

此题与1039的题目背景完全一样,输入与输出正好相反,思路也是类似的。只是本题,不需要在利用散列了。

这个题也可以用string来做,但是耗费的时间会长一些,用数字来代替字符串的比较会方便快捷很多。不过这个题,用string也可以过。

Code

use number

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <cstdio>
#include <vector>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 40010;
const int maxc = 2510;
char name[maxn][5];
vector<int> course[maxc];

bool cmp(int a, int b) {
return strcmp(name[a], name[b]) < 0;
}

int main(int argc, char const *argv[]) {
int n, k, c, courseID;
scanf("%d %d", &n, &k);
for(int i = 0; i < n; i++) {
scanf("%s %d", name[i], &c);
for(int j = 0; j < c; j++) {
scanf("%d", &courseID);
course[courseID].push_back(i);
}
}
for(int i = 1; i <= k; i++) {
printf("%d %d\n", i, course[i].size());
sort(course[i].begin(), course[i].end(), cmp);
for(int j = 0; j < course[i].size(); j++) {
printf("%s\n", name[course[i][j]]);
}
}
return 0;
}

use string

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
const int K = 2500 + 5;
vector<string> course[K];

int main() {
int n, k, course_num;
scanf("%d %d", &n, &k);
char name[5];
for(int i = 0; i < n; i++) {
scanf("%s %d", name, &course_num);
for(int j = 0; j < course_num; j++) {
int course_id;
scanf("%d", &course_id);
course[course_id].push_back(name);
}
}
for(int i = 1; i <= k; i++) {
sort(course[i].begin(), course[i].end());
printf("%d %d\n", i, course[i].size());
for(int j = 0; j < course[i].size(); j++) {
cout << course[i][j] << '\n';
}
}
return 0;
}

1048 Find Coins

Analysis

给定硬币种类和面值,按照题目要求输出和与题目相等两枚硬币,要求V1的面值小于等于V2。在输入时,利用散列的思路,先将每一枚硬币的个数统计下来。然后,利用sort将面值按升序排序,这样方便查找。输出时注意以下几点:

  1. V1V2相等时,要判断这枚硬币时候是否有两枚
  2. V1V2相等时,就已经是题目要求的最后一种情况了,若这种情况都不合条件,就没必要再继续查找下去了,所以使用一个标识flag来协助输出
  3. 注意所使用数组的下标,以免调用sort时出错
  4. 只要V1最小的那一组就行了,所以要在循环内调用break

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <cstdio>
#include <algorithm>
using namespace std;
const int MAXN = 100000 + 10;

int main(int argc, char const *argv[]) {
int N, M, coins[MAXN];
scanf("%d %d", &N, &M);
int value[MAXN] = {0};
for(int i = 1; i <= N; i++) {
scanf("%d", &coins[i]);
value[coins[i]]++;
}
sort(coins + 1, coins + N + 1);
int i, v1, v2;
bool flag = false;
for(i = 1; i <= N; i++) {
v1 = coins[i];
v2 = M - v1;
if(value[v1] && value[v2]) {
if(v1 == v2 && value[v1] != 2) {
break;
}
printf("%d %d", v1, v2);
flag = true;
break;
}
}
if(!flag) {
printf("No Solution");
}
return 0;
}

有了 C++ 的 map 就不需要在排序了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <iostream>
#include <map>
using namespace std;

int main() {
int n, m, tmp;
cin >> n >> m;
map<int, int> ht;
for(int i = 0; i < n; i++) {
cin >> tmp;
ht[tmp]++;
}
bool flag = false;
for(auto it = ht.begin(); it != ht.end(); it++) {
int diff = m - it->first;
if(diff == it->first) {
if(it->second >= 2) {
cout << it->first << ' ' << it->first;
flag = true;
break;
}
} else {
if(ht.count(diff)) {
cout << it->first << ' ' << diff;
flag = true;
break;
}
}
}
if(!flag) cout << "No Solution";
return 0;
}

再贴个二分的思路:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int main() {
int n, m;
cin >> n >> m;
vector<int> arr(n);
for(int i = 0; i < n; i++) {
cin >> arr[i];
}
sort(arr.begin(), arr.end());
bool flag = false;;
for(auto v1 = arr.begin(); v1 != arr.end(); v1++) {
auto v2 = lower_bound(arr.begin(), arr.end(), m - *v1);
if(v1 != v2 && *v1 + *v2 == m) {
cout << *v1 << ' ' << *v2;
flag = true;
break;
}
}
if(!flag) cout << "No Solution";
return 0;
}

1049 Counting Ones

Analysis

题意很简单,给定一个数字 n,算出从 1 到 n 所有的数字中 1 的个数和。

Code

这个题原来的时间限制是 10 ms,现在改成了 400 ms,所以直接暴力也能有 22 分。不过要想拿到满分,需要从数学的角度来分类讨论一下。
对于一个数的每一位数字 $mid$ 而言:

  1. 若 $mid$ 为 0,要使 $mid$ 一定能取到 1,那么其左边的数字只能取 $[0, n / 10 ^ {k+1} - 1]$,其中 k 是右边数字的位数,而其右边的数则可以取到 $[0, 10^k - 1]$,那么总共能取到的数字就是 $n / 10 ^ {k+1} \times 10^k$。
  2. 若 $mid$ 为 1,其左边的数字只能取 $[0, n / 10 ^ {k+1}]$,其中 $k$ 是右边数字的位数。此时,当左边数字取 $[0, n / 10 ^ {k+1} - 1]$ 时,右边数字可以取 $[0, 10 ^ k - 1]$;当左边数字取 $n / 10 ^ {k+1}$ 时,右边数字只能取 $[0, n \% 10^{k}]$。那么总共能取到的数字就是 $n / 10 ^ {k+1} \times 10^k + n % 10^{k} + 1$。
  3. 若 $mid$ 大于 1,左边能取到的数字就是 $[0, n / 10 ^ {k+1}]$,右边能取到的数字就是 $[0, 10 ^ k - 1]$,那么总共能取到的数字就是 $(n / 10 ^ {k+1} + 1) \times 10^k$。

所有数字中 1 的个数就是依次拆分数位分类讨论后的总和。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <iostream>
using namespace std;

int main() {
int n, ans = 0;
cin >> n;
int mask = 1, left, mid, right;
while(n / mask != 0) {
left = n / (mask * 10);
mid = n / mask % 10;
right = n % mask;
if(mid == 0) ans += left * mask;
else if(mid == 1) ans += left * mask + right + 1;
else ans += (left + 1) * mask;
mask *= 10;
}
cout << ans;
return 0;
}

这个题思路不是那么好想。

1050 String Subtraction

Analysis

利用散列的思想来处理,先遍历第一个字符串统计其中所有字符的出现次数(也可以只用truefalse来区分),然后遍历第二个字符串,将同时出现在两个字符串内的字符的次数标记为0,然后按照第一个字符串的顺序,输出标记不是0的字符即可。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <cstdio>
const int MAXN = 10000 + 5;

int main(int argc, char const *argv[]) {
char str1[MAXN], str2[MAXN];
fgets(str1, MAXN, stdin);
fgets(str2, MAXN, stdin);
int times[128] = {0};
char *p = str2;
while(*p != '\0') {
times[*p++] = 1;
}
p = str1;
while(*p != '\0') {
if(!times[*p]) {
putchar(*p);
}
p++;
}
return 0;
}

1051 Pop Sequence

Analysis

题目大意是给定一个栈的容量、出战序列长度和可能的出栈序列,判断在当前栈的长度下,出栈序列是否合法,若是,输出YES,反之,输出NO

按照题目的要求模拟栈的操作即可,使用 C++ 的stack容器可以很方便的完成这个需求。

注意每次判断要让栈清空,不然会影响判断。不过与其反复清空栈,不如直接新建一个。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <iostream>
#include <stack>
using namespace std;
const int maxn = 1000 + 5;
int seq[maxn] = {0};

int main() {
int n, m, k, tmp;
cin >> m >> n >> k;
while(k--) {
for(int i = 1; i <= n; i++) {
cin >> seq[i];
}
int index = 1;
bool flag = true;
stack<int> st;
for(int i = 1; i <= n; i++) {
st.push(i);
if(st.size() > m) {
flag = false;
break;
}
while(!st.empty() && st.top() == seq[index]) {
st.pop();
index++;
}
}
if(st.empty() && flag) cout << "YES" << endl;
else cout << "NO" << endl;
}
return 0;
}

1052 Linked List Sorting

Analysis

题目背景是属于链表的应用,实际是模拟链表的操作,使用静态链表模拟较为方便。

静态链表需要借助散列的概念,借助结构数组,使用题目给定的地址对应数组的下标,可以较为方便的存储结点值和下一个元素的地址。

题目要求的排序可以使用sort函数来完成,此时要注意由于题目可能会输入无效结点,所以需要增加一个flag来判断是否属于无效结点,这样sort函数才能将有效结点按序排好,并将无效结点排在最后一个有效结点的后面。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn = 100005;
struct Node {
int address, data, next;
bool flag;
} node[maxn];

bool cmp(Node a, Node b) {
if(a.flag == false || b.flag == false) {
return a.flag > b.flag;
} else {
return a.data < b.data;
}
}

int main(int argc, char const *argv[]) {
for(int i = 0; i < maxn; i++) {
node[i].flag = false;
}
int n, begin, address;
scanf("%d %d", &n, &begin);
for(int i = 0; i < n; i++) {
scanf("%d", &address);
scanf("%d %d", &node[address].data, &node[address].next);
node[address].address = address;
}
int count = 0, p = begin;
while(p != -1) {
node[p].flag = true;
count++;
p = node[p].next;
}
if(count == 0) {
printf("0 -1");
} else {
sort(node, node + maxn, cmp);
printf("%d %05d\n", count, node[0].address);
for(int i = 0; i < count; i++) {
if(i != count - 1) {
printf("%05d %d %05d\n", node[i].address, node[i].data,
node[i + 1].address);
} else {
printf("%05d %d -1\n", node[i].address, node[i].data);
}
}
}
return 0;
}

1053 Path of Equal Weight

Analysis

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
const int maxn = 110;
struct node {
int weight;
vector<int> child;
} Node[maxn];
bool cmp(int a, int b) {
return Node[a].weight > Node[b].weight;
}

int n, m, S;
int path[maxn];
void DFS(int index, int numNode, int sum) {
if(sum > S) return;
if(sum == S) {
if(Node[index].child.size() != 0) return;
for(int i = 0; i < numNode; i++) {
printf("%d", Node[path[i]].weight);
if(i < numNode - 1) printf(" ");
else printf("\n");
}
return;
}
for(int i = 0; i < Node[index].child.size(); i++) {
int child = Node[index].child[i];
path[numNode] = child;
DFS(child, numNode + 1, sum + Node[child].weight);
}
}

int main() {
scanf("%d %d %d", &n, &m, &S);
for(int i = 0; i < n; i++) {
scanf("%d", &Node[i].weight);
}
int id, k, child;
for(int i = 0; i < m; i++) {
scanf("%d %d", &id, &k);
for(int j = 0; j < k; j++) {
scanf("%d", &child);
Node[id].child.push_back(child);
}
sort(Node[id].child.begin(), Node[i].child.end(), cmp);
}
path[0] = 0;
DFS(0, 1, Node[0].weight);
return 0;
}

1054 The Dominant Color

Analysis

题目大意是给定一个矩阵,找出其中超过矩阵一半元素个数的值。题目保证测试样例中会有答案,也就是说,有一半的矩阵元素都是同一个数字,那么毫无疑问,这个元素的出现次数一定是这个矩阵所有元素出现次数的最大值,所以直接查找最大值即可。

由于像素点是由0-24位数字字符组成,所以需要将矩阵内元素当作字符串对待,同时需要建立与次数的唯一映射,使用 C++ 的map容器可以很方便的完成这个操作。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <iostream>
#include <map>
using namespace std;
map<string, int> color;

int main(int argc, char const *argv[]) {
int n, m, temp;
cin >> n >> m;
temp = n * m;
getchar();
while(temp--) {
string s;
cin >> s;
color[s]++;
}
temp = n * m;
map<string, int>::iterator max = color.begin();
map<string, int>::iterator it = color.begin();
for(; it != color.end(); it++) {
if(it->second > max->second) {
max = it;
}
}
cout << max->first;
return 0;
}

用 C++11 标准写简单一点:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>
#include <map>
using namespace std;
map<int, int> ht;

int main() {
int m, n, tmp;
cin >> m >> n;
for(int i = 0; i < n; i++) {
for(int j = 0; j < m; j++) {
cin >> tmp;
ht[tmp]++;
}
}
int ans, condition = (m * n) / 2;
for(auto &p: ht) {
if(p.second > condition) ans = p.first;
}
cout << ans;
return 0;
}

1055 The World’s Richest

Analysis

先按照题目要求排好序,然后按照题目给定的年龄区间进行输出,注意没有符合的输出时,需要输出None

此时,考虑到题目给的条件$M (\le 100)$,说明对于同一个年龄的数据,最多只输出100项。所以可以新建一个数组,然后按照排好序的序列,顺序保存每个年龄的数据,但只保存100个,这样在查找的时候能极大的节约时间。

尽管这道题在甲级题库内的时间限制是500ms,考试的时候说不定就是200ms了,要注意用最优解法。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXN = 100000 + 5;
int Age[MAXN] = {0};
struct people{
char name[10];
int age, worth;
} peo[MAXN], valid[MAXN];

bool cmp(people a, people b);

int main(int argc, char const *argv[]) {
int N, K;
scanf("%d %d", &N, &K);
for(int i = 0; i < N; i++) {
scanf("%s %d %d", peo[i].name, &peo[i].age, &peo[i].worth);
}
sort(peo, peo + N, cmp);
int validNum = 0;
for(int i = 0; i < N; i++) {
if(Age[peo[i].age] < 100) {
Age[peo[i].age]++;
valid[validNum++] = peo[i];
}
}
int M, Amin, Amax;
for(int i = 1; i <= K; i++) {
bool flag = false;
scanf("%d %d %d", &M, &Amin, &Amax);
printf("Case #%d:\n", i);
for(int j = 0; j < validNum && M; j++) {
if(Amin <= valid[j].age && valid[j].age <= Amax) {
printf("%s %d %d\n", valid[j].name, valid[j].age, valid[j].worth);
M--;
flag = true;
}
}
if(!flag) {
printf("None\n");
}
}
return 0;
}

bool cmp(people a, people b) {
if(a.worth != b.worth) return a.worth > b.worth;
else if(a.age != b.age) return a.age < b.age;
else return strcmp(a.name, b.name) < 0;
}

贴个 C++ 版:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 100000 + 5;
struct people {
string name;
int age, worth;
} peo[maxn], output[maxn];
int Age[maxn] = {0};
bool cmp(people a, people b) {
if(a.worth != b.worth) return a.worth > b.worth;
else if(a.age != b.age) return a.age < b.age;
else return a.name < b.name;
}
int main() {
int n, k;
cin >> n >> k;
for(int i = 0; i < n; i++) {
cin >> peo[i].name >> peo[i].age >> peo[i].worth;
}
sort(peo, peo + n, cmp);
int index = 0;
for(int i = 0; i < n; i++) {
if(Age[peo[i].age] < 100) {
Age[peo[i].age]++;
output[index++] = peo[i];
}
}
int M, amin, amax;
for(int i = 1; i <= k; i++) {
cout << "Case #" << i << ":" << endl;
cin >> M >> amin >> amax;
int cnt = M;
for(int i = 0; i < index; i++) {
if(amin <= output[i].age && output[i].age <= amax) {
cout << output[i].name << ' ' << output[i].age << ' ' << output[i].worth << endl;
if(--cnt == 0) break;
}
}
if(cnt == M) cout << "None" << endl;
}
return 0;
}

cin 和 cout 确实比 scanf 和 printf 慢了许多...

1056 Mice and Rice

Analysis

题目背景是一个叫做 Mice and Rice 的游戏,根据题目的描述可以知道,体重数字最大的老鼠就是胜利的老鼠,并且在本题中,老鼠之间的比赛需要分组进行,分组大小会给出。注意all the mice left will be put into the last group是指,由于可能存在最后一组老鼠少于分组大小的情况,默认将剩余的老鼠全部加入到下一轮比赛中。依次进行每一轮比赛,直至最后得到冠军老鼠,并输出所有老鼠的排名。

按照题目的意思,题目一开始会给定老鼠总数和分组大小,所以可以直接得到这一轮的分组数;同理,每一轮的分组数都可以这样得到。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#include <iostream>
#include <queue>
using namespace std;
const int maxn = 1010;
struct mouse{
int weight;
int r;
} mouse[maxn];

int main(int argc, char const *argv[]) {
int np, ng, order;
scanf("%d %d", &np, &ng);
for(int i = 0; i < np; i++) {
scanf("%d", &mouse[i].weight);
}
queue<int> q;
for(int i = 0; i < np; i++) {
scanf("%d", &order);
q.push(order);
}
int temp = np, group;
while(q.size() != 1) {
if(temp % ng == 0) group = temp / ng;
else group = temp / ng + 1;
for(int i = 0; i < group; i++) {
int k = q.front();
for(int j = 0; j < ng; j++) {
if(i * ng + j >= temp) break;
int front = q.front();
if(mouse[front].weight > mouse[k].weight) {
k = front;
}
mouse[front].r = group + 1;
q.pop();
}
q.push(k);
}
temp = group;
}
mouse[q.front()].r = 1;
for(int i = 0; i < np; i++) {
printf("%d", mouse[i].r);
if(i < np - 1) putchar(' ');
}
return 0;
}

1058 A+B in Hogwarts

Analysis

题目意思很简单,给你两个在霍格沃茨本地使用的货币数量,加起来就好。就跟生活中$100 + 150 = 250$块一样哈。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <cstdio>

struct money{
int g, k, s;
} A, B, Result;

int main(int argc, char const *argv[]) {
scanf("%d.%d.%d %d.%d.%d", &A.g, &A.s, &A.k, &B.g, &B.s, &B.k);
Result.g = A.g + B.g;
Result.k = A.k + B.k;
Result.s = A.s + B.s;
if(Result.k >= 29) {
Result.s += (Result.k / 29);
Result.k %= 29;
}
if(Result.s >= 17) {
Result.g += (Result.s / 17);
Result.s %= 17;
}
printf("%d.%d.%d\n", Result.g, Result.s, Result.k);
return 0;
}

贴个简单版:
k1 和 k2 的和可能会超过 int 的范围,所以要使用 long long。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <cstdio>

int main() {
long long g1, s1, k1, g2, s2, k2;
scanf("%lld.%lld.%lld %lld.%lld.%lld", &g1, &s1, &k1, &g2, &s2, &k2);
k1 += s1 * 29 + g1 * 29 * 17;
k2 += s2 * 29 + g2 * 29 * 17;
k1 += k2;
g1 = k1 / 29 / 17;
s1 = k1 / 29 % 17;
k1 = k1 % 29;
printf("%lld.%lld.%lld\n", g1, s1, k1);
return 0;
}

1059 Prime Factors

Analysis

题目大意是给定一个正整数,用质数对其进行分解,也即质因子分解。

既然需要用到质数,与其一个一个的判断,不如一开始先将素数表打印好,此题给定的数为long int,则素数表为$10^5$即可。

接着定义一个结构体数组,保存质因子和其个数。对于long int型的数而言,2 * 3 * 5 * 7 * 11 * 13 * 17 * 19 * 23 * 29就已经溢出了,所以结构体数组的大小取10以上即可。

从小到大枚举质因子,如果能整除给定的数,就进入循环,让这个数不断的整除它,从而计算这个质因子的数目。注意,n = 1时,需要特判输出1=1

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#include <cstdio>
#include <cmath>
const int maxn = 100010;

bool isPrime(int n) {
if(n <= 1) return false;
int sqr = sqrt(n);
for(int i = 2; i <= sqr; i++) {
if(n % i == 0) return false;
}
return true;
}

int prime[maxn], pNum = 0;
void filterPrime() {
for(int i = 1; i < maxn; i++) {
if(isPrime(i) == true) {
prime[pNum++] = i;
}
}
}
struct factor{
int x, cnt;
} fac[11];

int main(int argc, char const *argv[]) {
filterPrime();
int n, num = 0;
scanf("%d", &n);
if(n == 1) printf("1=1");
else {
printf("%d=", n);
int sqr = sqrt(n);
for(int i = 0; i < pNum && 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) putchar('*');
printf("%d", fac[i].x);
if(fac[i].cnt > 1) {
printf("^%d", fac[i].cnt);
}
}
}
return 0;
}

贴个 C++ 版的模拟做法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#include <cstdio>
#include <map>
#include <cmath>
using namespace std;
map<long long, int> factors;
bool isprime(long long n) {
if(n <= 1) return false;
else {
for(long long i = 2; i <= sqrt(n); i++) {
if(n % i == 0) return false;
}
return true;
}
}
int main() {
long long n, tmp, sqr;
scanf("%lld", &n);
printf("%lld=", n);
if(n == 1) printf("%lld", n);
else {
tmp = n;
sqr = sqrt(n);
for(long long fa = 2; fa <= sqr; fa++) {
if(tmp == 1) break;
if(isprime(fa)) {
while(tmp % fa == 0) {
factors[fa]++;
tmp /= fa;
}
}
}
if(factors.size() == 0) printf("%lld", n);
else {
auto it = factors.begin();
while(it != factors.end()) {
printf("%lld", it->first);
if(it->second != 1) printf("^%d", it->second);
it++;
if(it != factors.end()) printf("*");
}
}
}
return 0;
}

同样,一个数的最大因子不会超过它的算术平方根,所以循环边界直接用就好了。有了 map 之后,就可以很方便的统计质因子和对应的个数。

1060 Are They Equal

Analysis

这道题考察字符串处理,使用STL内的string容器,并调用其中的一些方法,会十分方便。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#include <iostream>
#include <string>
using namespace std;
int n;

string deal(string s, int &e);

int main(int argc, char const *argv[]) {
string s1, s2, s3, s4;
cin >> n >> s1 >> s2;
int e1 = 0, e2 = 0;
s3 = deal(s1, e1);
s4 = deal(s2, e2);
if(s3 == s4 && e1 == e2) {
cout << "YES 0." << s3 << "*10^" << e1 << endl;
} else {
cout << "NO 0." << s3 << "*10^" << e1 << " 0." << s4 << "*10^" << e2 << endl;
}
return 0;
}

string deal(string s, int &e) {
unsigned int k = 0;
while(s.length() > 0 && s[0] == '0') {
s.erase(s.begin());
}
if(s[0] == '.') {
s.erase(s.begin());
while(s.length() > 0 && s[0] == '0') {
s.erase(s.begin());
e--;
}
} else {
while(k < s.length() && s[k] != '.') {
k++;
e++;
}
if(k < s.length()) {
s.erase(s.begin() + k);
}
}
if(s.length() == 0) {
e = 0;
}
int num = 0;
k = 0;
string res;
while(num < n) {
if(k < s.length()) {
res += s[k++];
} else {
res += '0';
}
num++;
}
return res;
}

1061 Dating

Analysis

这道题与乙级题库的1014是一样的,不难,就是有些地方好像说的不太明确,比如,星期这个信息必须得是属于 $[A, G]$ 的大写字母才能可以进行判断...

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <stdio.h>
#include <string.h>
#include <ctype.h>

char *Week[7] = {
"MON", "TUE", "WED", "THU", "FRI", "SAT", "SUN",
};

int Hours[31] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
0, 0, 0, 0, 0, 0, 0,
10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23};

int main(int argc, char const *argv[]) {
char Str[5][65];
scanf("%s\n%s\n%s\n%s", Str[1], Str[2], Str[3], Str[4]);
int i, len1 = strlen(Str[1]), len2 = strlen(Str[2]), flag = 0, j;
for(i = 0; ; i++) {
if(!flag && Str[1][i] == Str[2][i] && ('A' <= Str[1][i] && Str[1][i] <= 'G')) {
printf("%s ", Week[Str[1][i] - 'A']);
flag = 1;
continue;
}
if(flag && Str[1][i] == Str[2][i] && \
(isdigit(Str[1][i]) || ('A' <= Str[1][i] && Str[1][i] <= 'N')) ) {
printf("%02d:", Hours[Str[1][i] - '0']);
break;
}
}
len1 = strlen(Str[3]), len2 = strlen(Str[4]);
for(j = 0; ; j++) {
if(Str[3][j] == Str[4][j] && isalpha(Str[3][j])) {
printf("%02d\n", j);
break;
}
}
return 0;
}

1062 Talent and Virtue

Analysis

此题与乙级题库 1015 一样。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXN = 100000 + 5;
struct student {
char id[10];
int scoreD, scoreC, sumDC, flag;
} stu[MAXN];
int N, L, H, M = 0;

bool cmp(student a, student b);

int main(int argc, char const *argv[]) {
scanf("%d %d %d", &N, &L, &H);
for(int i = 0; i < N; i++) {
scanf("%s %d %d", stu[i].id, &stu[i].scoreD, &stu[i].scoreC);
stu[i].sumDC = stu[i].scoreD + stu[i].scoreC;
if(stu[i].scoreC >= L && stu[i].scoreD >= L) {
if(stu[i].scoreD >= H && stu[i].scoreC >= H) {
stu[i].flag = 1;
} else if(stu[i].scoreD >= H && stu[i].scoreC >= L) {
stu[i].flag = 2;
} else if(stu[i].scoreC >= L && stu[i].scoreD >= L && stu[i].scoreD >= stu[i].scoreC) {
stu[i].flag = 3;
} else {
stu[i].flag = 4;
}
M++;
} else {
stu[i].flag = 5;
}
}
printf("%d\n", M);
sort(stu, stu + N, cmp);
for(int i = 0; i < M; i++) {
printf("%s %d %d\n", stu[i].id, stu[i].scoreD, stu[i].scoreC);
}
return 0;
}

bool cmp(student a, student b) {
if(a.flag != b.flag) return a.flag < b.flag;
else if(a.sumDC != b.sumDC) return a.sumDC > b.sumDC;
else if(a.scoreD != b.scoreD) return a.scoreD > b.scoreD;
else return strcmp(a.id, b.id) < 0;
}

1063 Set Similarity

Analysis

题目大意是给定若干个集合,给出两个集合的“相似程度”。这里的“相似程度”是指两个集合交集的元素个数除以两个集合并集的元素个数的百分比,且没有重复元素。

按照题目背景,使用 STL 的set来处理这个问题比较方便,优点如下:

  1. set在存储数据时,会自动去除重复数据
  2. set内元素的个数,可以直接使用set.size()得到
  3. 查找set内元素时,直接使用set.find(elements)即可

使用set读入所有输入数据后,开始查询。每次查询需要得到一个百分比,所以就需要求两个集合交集的元素个数和并集的元素个数。

具体方法是:遍历其中一个集合,令totalNum为另一个集合的元素个数,sameNum为相同元素的个数(初始化为0)。此时在另一个集合中查找当前遍历的集合中的元素,若存在,则sameNum++,反之则totalNum++,遍历结束后,需要的数字就算好了,接着相除得到百分比即可输出。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <cstdio>
#include <set>
using namespace std;
const int MAXN = 50 + 5;
set<int> st[MAXN];

void compare(int x, int y) {
int totalNum = st[y].size(), sameNum = 0;
for(set<int>::iterator it = st[x].begin(); it != st[x].end(); it++) {
if(st[y].find(*it) != st[y].end()) sameNum++;
else totalNum++;
}
printf("%.1lf%\n", sameNum * 100.0 / totalNum);
}

int main(int argc, char const *argv[]) {
int n, m, k, temp;
scanf("%d", &n);
for(int i = 1; i <= n; i++) {
scanf("%d", &m);
for(int j = 0; j < m; j++) {
scanf("%d", &temp);
st[i].insert(temp);
}
}
scanf("%d", &k);
while(k--) {
int s1, s2;
scanf("%d %d", &s1, &s2);
compare(s1, s2);
}
return 0;
}

写简单一点:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <iostream>
#include <set>
using namespace std;
const int maxn = 50 + 5;
set<int> st[maxn];

int main() {
int n, m, k;
cin >> n;
for(int i = 1; i <= n; i++) {
cin >> m;
for(int j = 0; j < m; j++) {
int tmp;
cin >> tmp;
st[i].insert(tmp);
}
}
cin >> k;
while(k--) {
int set1, set2, nc = 0, nt;
cin >> set1 >> set2;
nt = st[set2].size();
for(auto &tmp: st[set1]) {
if(st[set2].count(tmp)) nc++;
else nt++;
}
printf("%.1lf%%\n", nc * 100.0 / nt);
}
return 0;
}

1064 Complete Binary Search Tree

Analysis

题目大意是给定结点个数和结点值,建立一颗完全二叉排序树(CBT),根据名称,可以知道这类树既有完全二叉树的性质,又有二叉排序树的性质。

经过上面的分析,使用结构数组建树就十分方便,对完全二叉树而言,数组的下标即代表结点之间的关系,所以直接使用整型数组即可,并且在数组的顺序就是层次遍历的序列。接着要解决的问题就是将结点值赋给结点,根据二叉排序树的性质,利用中序遍历即可完成这个需求。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 1010;
int n, number[maxn], CBT[maxn], index = 0;

void inorder(int root) {
if(root > n) return;
inorder(2 * root);
CBT[root] = number[index++];
inorder(root * 2 + 1);
}

int main(int argc, char const *argv[]) {
cin >> n;
for(int i = 0; i < n; i++) {
cin >> number[i];
}
sort(number, number + n);
inorder(1);
for(int i = 1; i <= n; i++) {
cout << CBT[i];
if(i < n) cout << ' ';
}
return 0;
}

1065 A+B and C (64bit)

Analysis

这道题算是乙级题目1011 A+B 和 C的加强版了,题目给定的数据范围是$(-2^{63}, 2^{63})$,正好是64位带符号整型的数据范围,下面来分析可能出现的各种情况(只用对AB之和分析就好):

  1. AB之和仍然在$(-2^{63}, 2^{63})$之内,可以直接与C进行判断
  2. AB之和大于$2^{63}$,此时会发生正溢出,且其值的范围为:$[-2^{63}, -2]$(溢出进位,符号为从0变为1,所以为负,剩下63位构成的数字就在这个范围内了)。
  3. AB之和小于$-2^{63}$,此时会发生负溢出,其值范围为:$[0, 2^{63})$(原理类似)

对应上述三种情况,按照实际规则进行比大小即可。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <iostream>
using namespace std;
int main() {
long long t, a, b, c;
cin >> t;
for(int i = 1; i <= t; i++) {
cin >> a >> b >> c;
cout << "Case #" << i << ": ";
if(a + b < 0 && a > 0 && b > 0) cout << "true"; // positive overflow
else if(a + b >= 0 && a < 0 && b < 0) cout << "false"; // negative overflow
else if(a + b > c) cout << "true"; // normal
else cout << "false";
cout << endl;
}
return 0;
}

以上是原来未更新测试数据之前的 AC 代码,现在只能拿到 16 分了,最后一个测试点无法通过。
究其原因,其实是这个题目又开始玩文字游戏了,C 的范围是 $(2^{-63}, 2^{63})$,但 A 和 B 不是的,也就是说 A 和 B 的位数可能要超过 9223372036854775807。
从这里开始,这个题考察的内容就不再是对数据溢出的判断了,那考察什么?考察的是cinscanf 从输入流获取输入的差别,也不知道这样改是为了什么😓。
至于cinscanf有什么区别,得单独写文章总结,现在贴出 AC 的代码(其实就只是换掉了cin而已):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <iostream>
using namespace std;
int main() {
long long t, a, b, c;
cin >> t;
for(int i = 1; i <= t; i++) {
scanf("%lld %lld %lld", &a, &b, &c);
cout << "Case #" << i << ": ";
if(a + b < 0 && a > 0 && b > 0) cout << "true"; // positive overflow
else if(a + b >= 0 && a < 0 && b < 0) cout << "false"; // negative overflow
else if(a + b > c) cout << "true"; // normal
else cout << "false";
cout << endl;
}
return 0;
}

看到这里,一上来就用cin的人,估计要被气吐血了。按照出题人的意图和这道题的分值而言,考察了溢出的相关知识就可以了。这样改了之后,还需要对库函数有一定的了解。当然,直接上来就用scanf的,当我没说。
但针对这道题而言,还有一种做法,那就是选用更高精度的数据类型 long double,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>
using namespace std;
int main() {
int t;
cin >> t;
for(int i = 1; i <= t; i++) {
long double a, b, c;
cin >> a >> b >> c;
cout << "Case #" << i << ": ";
if(a + b < 0 && a > 0 && b > 0) cout << "true"; // positive overflow
else if(a + b >= 0 && a < 0 && b < 0) cout << "false"; // negative overflow
else if(a + b > c) cout << "true"; // normal
else cout << "false";
cout << endl;
}
return 0;
}

在 C++11 标准中测试,long double的数据类型占了 16 个字节,能表示相当大的数了。

1066 Root of AVL Tree

Analysis

题目大意给定一棵树的结点个数,再给定各个结点的值,建立一颗平衡二叉树(AVL),然后输出结点的值即可。

由于题目需要建立 AVL 树,依据 AVL 树的性质,每个结点的平衡因子绝对值不能大于1,所以在插入每个结点时,需要对树进行调整,使其满足 AVL 树的性质。

AVL 树失衡的情况总共有4种:LL、LR、RR 和 RL 四种,会根据每种情况做对应的旋转即可。注意每次插入结点时都需要检查树是否失衡,这样能够及时调整。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 25;
struct node {
int v, height;
node *left, *right;
} *root;
int n;

node *newnode(int v) {
node *Node = new node;
Node->v = v;
Node->height = 1;
Node->left = Node->right = NULL;
return Node;
}

int getheight(node *root) {
if(root == NULL) return 0;
return root->height;
}

void updateheight(node *root) {
root->height = max(getheight(root->left), getheight(root->right)) + 1;
}

int getbalancefactor(node *root) {
return getheight(root->left) - getheight(root->right);
}

void leftRotation(node *&root) {
node *temp = root->right;
root->right = temp->left;
temp->left = root;
updateheight(root);
updateheight(temp);
root = temp;
}

void rightRotation(node *&root) {
node *temp = root->left;
root->left = temp->right;
temp->right = root;
updateheight(root);
updateheight(temp);
root = temp;
}

void insert(node *&root, int v) {
if(root == NULL) {
root = newnode(v);
return;
}
if(v < root->v) {
insert(root->left, v);
updateheight(root);
if(getbalancefactor(root) == 2) {
if(getbalancefactor(root->left) == 1) {
rightRotation(root);
} else if(getbalancefactor(root->left) == -1) {
leftRotation(root->left);
rightRotation(root);
}
}
} else {
insert(root->right, v);
updateheight(root);
if(getbalancefactor(root) == -2) {
if(getbalancefactor(root->right) == -1) {
leftRotation(root);
} else if(getbalancefactor(root->right) == 1) {
rightRotation(root->right);
leftRotation(root);
}
}
}
}

int main(int argc, char const *argv[]) {
cin >> n;
int value;
for(int i = 0; i < n; i++) {
cin >> value;
insert(root, value);
}
cout << root->v;
return 0;
}

1067 Sort with Swap

Analysis

这道题考察贪心,参杂了一些模拟。

对待贪心类的题目,必须得找准贪心的策略,不然就没法解题了,得仔细观察样例。假设数字都存储在数组中,按照题目的说明,可以发现:0值每次交换的对象都是下标值与其本身值不一样的数字。所以,每次将0值与具有上述特点的值交换即可;但要注意,若0的下标为0时,算法就无法继续进行了,此时需要特别处理下,将0与当前值最小且具有上述特点的数字直接进行交换。

这时可以发现,如果从数组头部开始向后查找这样的数字,就会有很多已经排好的数被遍历到。为了避免这样的情况,需要将当前值最小且具有上述特点的数字保存在一个变量内,这样下次查找时直接从这个数字开始就可以避免重复查找的情况了。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <cstdio>
#include <algorithm>
using namespace std;
const int MAXN = 100000 + 10;
int pos[MAXN];

int main(int argc, char const *argv[]) {
int n, ans = 0;
scanf("%d", &n);
int left = n - 1, num;
for(int i = 0; i < n; i++) {
scanf("%d", &num);
pos[num] = i;
if(num == i && num != 0) {
left--;
}
}
int k = 1;
while(left > 0) {
if(pos[0] == 0) {
while(k < n) {
if(pos[k] != k) {
swap(pos[0], pos[k]);
ans++;
break;
}
k++;
}
}
while(pos[0] != 0) {
swap(pos[0], pos[pos[0]]);
ans++;
left--;
}
}
printf("%d\n", ans);
return 0;
}

贴个 C++ 版:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <iostream>
#include <unordered_map>
using namespace std;
const int maxn = 100000 + 5;
int arr[maxn];
unordered_map<int, int> numandindex;

int main() {
int n, cnt = 0;
cin >> n;
for(int i = 0; i < n; i++) {
cin >> arr[i];
numandindex[arr[i]] = i;
}
int index0 = numandindex[0], i = 0;
while(true) {
if(index0 == 0) {
for(; i < n; i++) {
if(arr[i] != i) break;
}
if(i != n) {
numandindex[arr[i]] = 0;
numandindex[0] = i;
} else break;
}
int index = numandindex[index0];
swap(arr[index0], arr[index]);
cnt++;
index0 = index;
}
cout << cnt;
return 0;
}

本质上是下标在交换,所以用一个 map 来建立数组元素与对应下标的映射,这样理解起来会清楚一些。

1069 The Black Hole of Numbers

Analysis

此题与乙级题库的1019一样

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include <cstdio>
#include <algorithm>
using namespace std;

void toArray(int n, int *array) {
int temp = n, i = 0, ret = 0;
while(temp) {
array[i++] = temp % 10;
temp /= 10;
}
}

int main(int argc, char const *argv[]) {
int n, min, max, diff;
scanf("%d", &n);
while(1) {
int num[5] = {0};
toArray(n, num);
sort(num, num + 4);
max = num[0] + num[1] * 10 + num[2] * 100 + num[3] * 1000;
min = num[3] + num[2] * 10 + num[1] * 100 + num[0] * 1000;
diff = max - min;
if(!diff) {
printf("%04d - %04d = 0000\n", max, min);
break;
} else {
printf("%04d - %04d = %04d\n", max, min, diff);
if(diff == 6174) break;
n = diff;
}
}

return 0;
}

1070 Mooncake

Analysis

此题与乙级题库的1020类似(好像只是数据不一样),考察贪心。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <cstdio>
#include <algorithm>
using namespace std;
const int MAXN = 1000 + 5;
struct mooncake{
double store, sell, price;
} cake[MAXN];
bool cmp(mooncake a, mooncake b);

int main(int argc, char const *argv[]) {
int N;
double D;
scanf("%d %lf", &N, &D);
for(int i = 0; i < N; i++) {
scanf("%lf", &cake[i].store);
}
for(int i = 0; i < N; i++) {
scanf("%lf", &cake[i].sell);
cake[i].price = cake[i].sell / cake[i].store;
}
sort(cake, cake + N, cmp);
double ans = 0;
for(int i = 0; i < N; i++) {
if(cake[i].store <= D) {
ans += cake[i].sell;
D -= cake[i].store;
} else {
ans += cake[i].price * D;
break;
}
}
printf("%.2lf\n", ans);
return 0;
}

bool cmp(mooncake a, mooncake b) {
return a.price > b.price;
}

1071 Speech Patterns

Analysis

题目要求输入一句话,输出其中出现次数最长的字符串,字符串只能包含0-9A-Za-z内的字符,其他字符均被认为是字符串之间的分隔符。

先将字符串整行读入,在逐个拆分出每个单词,并利用map来建立字符串(string)与次数(int)之间的映射,每统计到相同的字符串,次数加1。

输出时,遍历map,找出其中出现次数最多的字符串即可。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#include <iostream>
#include <string>
#include <map>
using namespace std;
map<string, int> mp;

bool check(char c) {
if('0' <= c && c <= '9') return true;
if('a' <= c && c <= 'z') return true;
if('A' <= c && c <= 'Z') return true;
return false;
}

int main(int agrc, char const *argv[]) {
map<string, int> count;
string str;
getline(cin, str);
int i = 0;
while(i < str.length()) {
string word;
while(i < str.length() && check(str[i]) == true) {
if('A' <= str[i] && str[i] <= 'Z') {
str[i] += 32;
}
word += str[i];
i++;
}
if(word != "") {
if(count.find(word) == count.end()) count[word] = 1;
else count[word]++;
}
while(i < str.length() && check(str[i]) == false) {
i++;
}
}
string ans;
int max = 0;
for(map<string, int>::iterator it = count.begin(); it != count.end(); it++) {
if(it->second > max) {
max = it->second;
ans = it->first;
}
}
cout << ans << ' ' << max;
return 0;
}

写简单一点:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <iostream>
#include <map>
#include <cctype>
using namespace std;
map<string, int> stringcnt;
const int maxn = 1048576 + 10;

int main() {
string str, tmp;
getline(cin, str);
int maxcnt = 0;
for(int i = 0; i < str.length(); i++) {
if(isalnum(str[i])) {
if(isupper(str[i])) str[i] = tolower(str[i]);
tmp.push_back(str[i]);
}
if(!isalnum(str[i]) || i == str.length() - 1) {
if(tmp != "") {
stringcnt[tmp]++;
maxcnt = max(maxcnt, stringcnt[tmp]);
}
tmp.clear();
}
}
for(auto &p: stringcnt) {
if(p.second == maxcnt) {
cout << p.first << ' ' << p.second;
break;
}
}
return 0;
}

以为可以直接用空格字符作为单词的分隔符,结果仔细一看Here a "word" is defined as a continuous sequence of alphanumerical characters separated by non-alphanumerical characters or the line beginning/end.,也就是说题目没说一定会用空格来分隔单词,这样就没法利用 cin 和 scanf 自动按空格读入特性了,只能获取一行后逐个提取出来。最后一个单词的结尾也可能是字母、数字,所以也要统计在内,测试点 4 应该是这样。

1072 Gas Station

Analysis

题目大意是给定若干个源点和固定点,求这些源点到所有固定点距离最小的源点,如果存在相同解,就输出平均距离最小的源点。

按照题目大意,可以将题目描述抽象为图,接着利用 Dijkstra 算法就可以求解源点到固定点的最短距离;由于题目给定的源点有多个,所以要使用多次 Dijkstra 算法,所以每次执行算法之前需要将用到的bool数组初始化为false。然后,按照题目条件来判断或筛选最优解。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxv = 1020;
const int inf = 0x3fffffff;
int n, m, k, ds, G[maxv][maxv];
int d[maxv];
bool vis[maxv] = {false};
void dijkstra(int s) {
memset(vis, false, sizeof(vis)); //do not forget initializing this array
fill(d, d + maxv, inf);
d[s] = 0;
for(int i = 0; i < n + m; i++) {
int u = -1, min = inf;
for(int j = 1; j <= n + m; j++) {
if(vis[j] == false && d[j] < min) {
min = d[j];
u = j;
}
}
if(u == -1) return;
vis[u] = true;
for(int v = 1; v <= n + m; v++) {
if(vis[v] == false && G[u][v] != inf) {
if(d[v] > d[u] + G[u][v]) d[v] = d[u] + G[u][v];
}
}
}
}
int getid(char str[]) { //tranfer the id of gas station
int len = strlen(str), id = 0;
for(int i = 0; i < len; i++) {
if(str[i] != 'G') id = id * 10 + (str[i] - '0');
}
if(str[0] == 'G') return n + id;
else return id;
}
int main(int argc, char const *argv[]) {
scanf("%d %d %d %d", &n, &m, &k, &ds);
int u, v, w;
char city1[5], city2[5];
fill(G[0], G[0] + maxv * maxv, inf);
for(int i = 0; i < k; i++) {
scanf("%s %s %d", city1, city2, &w);
u = getid(city1);
v = getid(city2);
G[v][u] = G[u][v] = w;
}
double ansdis = -1, ansavg = inf;
int ansid = -1;
for(int i = n + 1; i <= n + m; i++) {
double mindis = inf, avg = 0;
dijkstra(i); //every station should execute this dijkstra
for(int j = 1; j <=n; j++) {
if(d[j] > ds) { //this solution does not fit the problem
mindis = -1;
break;
}
if(d[j] < mindis) mindis = d[j]; //cal minimum of distance
avg += 1.0 * d[j] / n; //calculate the average
}
if(mindis == -1) continue;
if(mindis > ansdis) { //more optimal solution
ansid = i;
ansdis = mindis;
ansavg = avg;
} else if(mindis == ansdis && avg < ansavg) { //more optimal solution
ansid = i;
ansavg = avg;
}
}
if(ansid == -1) printf("No Solution\n");
else {
printf("G%d\n", ansid - n);
printf("%.1lf %.1lf\n", ansdis, ansavg);
}
return 0;
}

1073 Scientific Notation

Analysis

此题与乙级题库的1024一样。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include <cstdio>
const int MAXN = 10000 + 5;

int main(int argc, char const *argv[]) {
char Num[MAXN];
scanf("%s", Num);
int Epos, exp = 0;
for(Epos = 1; Num[Epos] != 'E'; Epos++);
for(int i = Epos + 2; Num[i] != '\0'; i++) {
exp = exp * 10 + Num[i] - '0';
}
if(Num[0] == '-') {
putchar(Num[0]);
}
if(exp == 0) {
for(int i = 1; Num[i] != 'E'; i++) {
putchar(Num[i]);
}
} else if(Num[Epos + 1] == '-') {
printf("0.");
for(int i = exp - 1; i > 0; i--) {
putchar('0');
}
for(int i = 1; Num[i] != 'E'; i++) {
if(Num[i] == '.') continue;
putchar(Num[i]);
}
} else if(Num[Epos + 1] == '+') {
for(int i = 1; i < Epos; i++) {
if(Num[i] == '.') continue;
putchar(Num[i]);
if(i == exp + 2 && Epos - 3 != exp) {
putchar('.');
}
}
for(int i = 0; i < exp - (Epos - 3); i++) {
putchar('0');
}
}
putchar('\n');
return 0;
}

1074 Reversing Linked List

Analysis

此题与乙级题库的1025一样。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 100005;
struct node{
int address, data, next;
int order;
} Node[maxn];

bool cmp(node a, node b) {
return a.order < b.order;
}

int main(int argc, char const *argv[]) {
for(int i = 0; i < maxn; i++) {
Node[i].order = maxn;
}
int head, n, k, address;
scanf("%d %d %d", &head, &n, &k);
for(int i = 0; i < n; i++) {
scanf("%d", &address);
scanf("%d %d", &Node[address].data, &Node[address].next);
Node[address].address = address;
}
int p = head, count = 0;
while(p != -1) {
Node[p].order = count++;
p = Node[p].next;
}
sort(Node, Node + maxn, cmp);
n = count;
for(int i = 0; i < n / k; i++) {
for(int j = (i + 1) * k - 1; j > i * k; j--) {
printf("%05d %d %05d\n", Node[j].address, Node[j].data,
Node[j - 1].address);
}
printf("%05d %d ", Node[i * k].address, Node[i * k].data);
if(i < n / k - 1) {
printf("%05d\n", Node[(i + 2) * k - 1].address);
} else {
if(n % k == 0) {
printf("-1\n");
} else {
printf("%05d\n", Node[(i + 1) * k].address);
for(int i = n / k * k; i < n; i++) {
printf("%05d %d ", Node[i].address, Node[i].data);
if(i < n - 1) {
printf("%05d\n", Node[i + 1].address);
} else {
printf("-1\n");
}
}
}
}
}
return 0;
}

1075 PAT Judge

Analysis

考察排序,题目说明比较多,要仔细读题。关键是输入数据的处理,处理后要达到便于排序(与题目一致)和输出的效果。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXN = 10000 + 5;
struct user{
int id, score[6], sum, perfect;
bool flag;
} us[MAXN];
int N, K, M;
int full[6] = {0};
bool cmp(user a, user b);
void Init();

int main(int argc, char const *argv[]) {
scanf("%d %d %d", &N, &K, &M);
Init();
for(int i = 1; i <= K; i++) {
scanf("%d", full + i);
}
int uid, pid, score_ob;
for(int i = 0; i < M; i++) {
scanf("%d %d %d", &uid, &pid, &score_ob);
if(score_ob != -1) {
us[uid].flag = true;
}
if(score_ob == -1 && us[uid].score[pid] == -1) {
us[uid].score[pid] = 0;
}
if(score_ob == full[pid] && us[uid].score[pid] < full[pid]) {
us[uid].perfect++;
}
if(score_ob > us[uid].score[pid]) {
us[uid].score[pid] = score_ob;
}
}
for(int i = 1; i <= N; i++) {
for(int j = 1; j <= K; j++) {
if(us[i].score[j] != -1) {
us[i].sum += us[i].score[j];
}
}
}
sort(us + 1, us + N + 1, cmp);
int r = 1;
for(int i = 1; i <= N && us[i].flag == true; i++) {
if(i > 1 && us[i].sum != us[i - 1].sum) {
r = i;
}
printf("%d %05d %d", r, us[i].id, us[i].sum);
for(int j = 1; j <= K; j++) {
if(us[i].score[j] == -1) {
printf(" -");
} else {
printf(" %d", us[i].score[j]);
}
}
putchar('\n');
}
return 0;
}

bool cmp(user a, user b) {
if(a.sum != b.sum) return a.sum > b.sum;
else if(a.perfect != b.perfect) return a.perfect > b.perfect;
else return a.id < b.id;
}

void Init() {
for(int i = 1; i <= N; i++) {
us[i].id = i;
us[i].sum = 0;
us[i].perfect = 0;
us[i].flag = false;
memset(us[i].score, -1, sizeof(us[i].score));
}
}

重新写了一下,整体思路不变:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 10000 + 5;
struct student {
int id, grade[6], cnt;
bool flag;
} stu[maxn];
int perfect[6], n, k, m;
bool cmp(student a, student b) {
if(a.grade[0] != b.grade[0]) return a.grade[0] > b.grade[0];
else if(a.cnt != b.cnt) return a.cnt > b.cnt;
else return a.id < b.id;
}
void Init() {
for(int i = 0; i < maxn; i++) {
stu[i].id = i;
stu[i].cnt = 0;
stu[i].flag = false;
memset(stu[i].grade, -1, sizeof(stu[i].grade));
stu[i].grade[0] = 0;
}
}
int main() {
scanf("%d %d %d", &n, &k, &m);
Init();
for(int i = 1; i <= k; i++) {
scanf("%d", &perfect[i]);
}
int id, grade, pronum;
for(int i = 0; i < m; i++) {
scanf("%d %d %d", &id, &pronum, &grade);
if(grade != -1) stu[id].flag = true;
if(grade == -1 && stu[id].grade[pronum] == -1) stu[id].grade[pronum] = 0;
if(grade == perfect[pronum] && stu[id].grade[pronum] < perfect[pronum]) stu[id].cnt++;
if(grade > stu[id].grade[pronum]) stu[id].grade[pronum] = grade;
}
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= k; j++) {
if(stu[i].grade[j] > 0) stu[i].grade[0] += stu[i].grade[j];
}
}
sort(stu + 1, stu + n + 1, cmp);
int rank = 1;
for(int i = 1; i <= n && stu[i].flag; i++) {
if(i > 1 && stu[i].grade[0] != stu[i - 1].grade[0]) rank = i;
printf("%d %05d %d", rank, stu[i].id, stu[i].grade[0]);
for(int j = 1; j <= k; j++) {
if(stu[i].grade[j] == -1) printf(" -");
else printf(" %d", stu[i].grade[j]);
}
putchar('\n');
}
return 0;
}

1076 Forwards on Weibo

Analysis

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#include <iostream>
#include <queue>
#include <cstring>
#include <vector>
using namespace std;
const int maxn = 1010;
struct node {
int id;
int layer;
};
vector<node> Adj[maxn];
bool inq[maxn] = {false};
int BFS(int s, int L) {
int numFoward = 0;
queue<node> q;
node start;
start.id = s;
start.layer = 0;
q.push(start);
inq[start.id] = true;
while(!q.empty()) {
node top = q.front();
q.pop();
int u = top.id;
for(int i = 0; i < Adj[u].size(); i++) {
node next = Adj[u][i];
next.layer = top.layer + 1;
if(inq[next.id] == false && next.layer <= L) {
q.push(next);
inq[next.id] = true;
numFoward++;
}
}
}
return numFoward;
}

int main(int argc, char const *argv[]) {
node user;
int n, L, numFollow, idFollow;
cin >> n >> L;
for(int i = 1; i <= n; i++) {
user.id = i;
cin >> numFollow;
for(int j = 0; j < numFollow; j++) {
cin >> idFollow;
Adj[idFollow].push_back(user);
}
}
int numQuery, s;
cin >> numQuery;
while(numQuery--) {
memset(inq, false, sizeof(inq));
cin >> s;
int numFoward = BFS(s, L);
cout << numFoward << endl;
}
return 0;
}

1077 Kuchiguse

Analysis

本题的实质是在求字符串的最长相同后缀,从后遍历字符串比较麻烦,所以采取先逆转字符串,然后从前遍历的做法,这样就会方便许多。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include <cstdio>
#include <cstring>

const int MAXN = 256 + 5;
char str[100][MAXN];
void Reverse(char *s);

int main(int argc, char const *argv[]) {
int N, minLen = 256, ans = 0;
scanf("%d", &N);
getchar();
for(int i = 0; i < N; i++) {
fgets(str[i], MAXN, stdin);
int len = strlen(str[i]);
if(len < minLen) minLen = len;
Reverse(str[i]);
}
for(int i = 0; i < minLen; i++) {
char c = str[0][i];
bool same = true;
for(int j = 1; j < N; j++) {
if(c != str[j][i]) {
same = false;
break;
}
}
if(same) {
ans++;
} else {
break;
}
}
if(ans > 1) {
for(int i = ans - 1; i >= 0; i--) {
putchar(str[0][i]);
}
} else {
puts("nai");
}
return 0;
}

void Reverse(char *s) {
char temp;
int len = strlen(s);
for(int i = 0; i < len / 2; i++) {
temp = s[i];
s[i] = s[len - i - 1];
s[len - i - 1] = temp;
}
}

贴个 C++ 版:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int main() {
int n, minlen = 0x3fffffff;
cin >> n;
getchar();
vector<string> strs;
for(int i = 0; i < n; i++) {
string tmp;
getline(cin, tmp);
reverse(tmp.begin(), tmp.end());
strs.push_back(tmp);
if(tmp.length() < minlen) minlen = tmp.length();
}
string ans;
bool flag = false;
for(int i = 0; i < minlen; i++) {
char tmp = strs[0][i];
for(int j = 1; j < n; j++) {
if(strs[j][i] != tmp) {
flag = true;
break;
}
}
if(flag) break;
ans += tmp;
}
reverse(ans.begin(), ans.end());
if(ans != "") cout << ans;
else cout << "nai";
return 0;
}

1078 Hashing

Analysis

题目大意是用线性探测的方法,构造哈希表,用平方探测的办法解决冲突。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#include <cstdio>
#include <cmath>
const int MAXM = 10005;
bool isPrime(int n) {
if(n <= 1 || (n != 2 && n % 2 == 0)) {
return false;
} else {
for(int i = 3; i <= sqrt(n); i += 2) {
if(n % i == 0) return false;
}
}
return true;
}

int nearPrime(int n) {
while(!isPrime(n)) n++;
return n;
}
int hashTable[MAXM] = {0};

int main(int argc, char const *argv[]) {
int m, n, temp, index;
scanf("%d %d", &m, &n);
m = nearPrime(m);
for(int i = 0; i < n; i++) {
scanf("%d", &temp);
index = temp % m;
if(hashTable[index] == 0) {
hashTable[index] = temp;
printf("%d", index);
} else {
int step;
for(step = 1; step < m; step++) {
index = (temp + step * step) % m;
if(hashTable[index] == 0) {
hashTable[index] = temp;
printf("%d", index);
break;
}
}
if(step >= m) {
printf("-");
}
}
if(i < n - 1) putchar(' ');
}
return 0;
}

1079 Total Sales of Supply

Analysis

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
const int maxn = 110;
struct node {
int weight;
vector<int> child;
} Node[maxn];
bool cmp(int a, int b) {
return Node[a].weight > Node[b].weight;
}

int n, m, S;
int path[maxn];
void DFS(int index, int numNode, int sum) {
if(sum > S) return;
if(sum == S) {
if(Node[index].child.size() != 0) return;
for(int i = 0; i < numNode; i++) {
printf("%d", Node[path[i]].weight);
if(i < numNode - 1) printf(" ");
else printf("\n");
}
return;
}
for(int i = 0; i < Node[index].child.size(); i++) {
int child = Node[index].child[i];
path[numNode] = child;
DFS(child, numNode + 1, sum + Node[child].weight);
}
}

int main() {
scanf("%d %d %d", &n, &m, &S);
for(int i = 0; i < n; i++) {
scanf("%d", &Node[i].weight);
}
int id, k, child;
for(int i = 0; i < m; i++) {
scanf("%d %d", &id, &k);
for(int j = 0; j < k; j++) {
scanf("%d", &child);
Node[id].child.push_back(child);
}
sort(Node[id].child.begin(), Node[i].child.end(), cmp);
}
path[0] = 0;
DFS(0, 1, Node[0].weight);
return 0;
}

1080 Graduate Admission

Analysis

这个题相当麻烦,基本思想是排序 + 贪心。
排序的规则很简单,第一判断依据是总分(不用与题目的计算公式一致),第二排序依据是 Ge 这个分数,顺序为非增序。排序的问题比较容易解决,难点在学校挑选学生上。
具体而言,整个录取过程是一个贪心的过程。首先按照分数,将每位学生的排名求出。然后根据排名,按照每位学生的选择,依次进行录取。之所以说是贪心,是因为以前面的选择优先(也就是第一志愿优先的规则),前面选择的学校名额不足时就顺排到后面的学校。
由于题目还要求,对于排名相同且选择相同学校的,学校应该扩额录取。所以需要记录下,在不超过限额的情况,每个学校能录取的最后一名的名次,并与后面的学生进行比较,如果排名相同,就得录取。
最后还有一点,学校的录取名单需要按照 id 非降序排序。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
#include <cstdio>
#include <algorithm>
using namespace std;
const int MAXN = 40000 + 5;

struct student{
int ge, gi, sum;
int r, id;
int cho[6];
} stu[MAXN];

struct school{
int quota;
int stuNum;
int id[MAXN];
int lastAdmit;
} sch[110];

bool cmpStu(student a, student b);
bool cmpID(int a, int b);
int main(int argc, char const *argv[]) {
int N, M, K;
scanf("%d %d %d", &N, &M, &K);
for(int i = 0; i < M; i++) {
scanf("%d", &sch[i].quota);
sch[i].stuNum = 0;
sch[i].lastAdmit = -1;
}
for(int i = 0; i < N; i++) {
stu[i].id = i;
scanf("%d %d", &stu[i].ge, &stu[i].gi);
stu[i].sum = stu[i].ge + stu[i].gi;
for(int j = 0; j < K; j++) {
scanf("%d", &stu[i].cho[j]);
}
}
sort(stu, stu + N, cmpStu);
for(int i = 0; i < N; i++) {
if(i > 0 && stu[i].sum == stu[i - 1].sum
&& stu[i].ge == stu[i - 1].ge) {
stu[i].r = stu[i - 1].r;
} else {
stu[i].r = i;
}
}
for(int i = 0; i < N; i++) {
for(int j = 0; j < K; j++) {
int choice = stu[i].cho[j];
int num = sch[choice].stuNum;
int last = sch[choice].lastAdmit;
if(num < sch[choice].quota || (last != -1 &&
stu[i].r == stu[last].r)) {
sch[choice].id[num] = i;
sch[choice].lastAdmit = i;
sch[choice].stuNum++;
break;
}
}
}
for(int i = 0; i < M; i++) {
if(sch[i].stuNum > 0) {
sort(sch[i].id, sch[i].id + sch[i].stuNum, cmpID);
for(int j = 0; j < sch[i].stuNum; j++) {
printf("%d", stu[sch[i].id[j]].id);
if(j < sch[i].stuNum - 1) {
printf(" ");
}
}
}
putchar('\n');
}
return 0;
}

bool cmpStu(student a, student b) {
if(a.sum != b.sum) return a.sum > b.sum;
else return a.ge > b.ge;
}

bool cmpID(int a, int b) {
return stu[a].id < stu[b].id;
}

贴个 C++ 版:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
const int maxn = 40000 + 5;
struct student {
int ge, gi, id, rank;
int sum;
int choices[6];
} stu[maxn];
int n, m, k;
int quota[105] = {0};
int lastrank[105] = {0};
bool cmp(student a, student b) {
if(a.sum != b.sum) return a.sum > b.sum;
else return a.ge > b.ge;
}
int main() {
cin >> n >> m >> k;
for(int i = 0; i < m; i++) {
cin >> quota[i];
}
for(int i = 0; i < n; i++) {
cin >> stu[i].ge >> stu[i].gi;
stu[i].sum = stu[i].ge + stu[i].gi;
stu[i].id = i;
for(int j = 0; j < k; j++) {
cin >> stu[i].choices[j];
}
}
sort(stu, stu + n, cmp);
stu[0].rank = 1;
for(int i = 1; i < n; i++) {
if(stu[i].sum == stu[i - 1].sum && stu[i].ge == stu[i - 1].ge) stu[i].rank = stu[i - 1].rank;
else stu[i].rank = i + 1;
}
vector<vector<int>> ans(105);
for(int i = 0; i < n; i++) {
for(int j = 0; j < k; j++) {
int school = stu[i].choices[j];
if(quota[school] != 0) {
ans[school].push_back(stu[i].id);
quota[school]--;
lastrank[school] = stu[i].rank;
break;
} else {
if(stu[i].rank == lastrank[school]) {
ans[school].push_back(stu[i].id);
break;
}
}
}
}
for(int i = 0; i < m; i++) {
int size = ans[i].size();
if(size == 0) {
cout << endl;
continue;
} else {
sort(ans[i].begin(), ans[i].end());
cout << ans[i][0];
for(int j = 1; j < size; j++) {
cout << ' ' << ans[i][j];
}
cout << endl;
}
}
return 0;
}

1081 Rational Sum

Analysis

题目大意是给定Na/b形式的分数,a为分子,b为分母,求这N个分数的和再输出。

给定的分数只有两种情况:真分数和假分数,不存在带分数,但输出要输出带分数,并且是最简形式。化简的目的其实题目考察求最大公约数,利用欧几里得算法即可求得两个数的最大公约数。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#include <cstdio>
#include <cstdlib>

typedef struct fraction {
long long up, down;
} Fraction;

long long gcd(long long a, long long b) {
return b == 0 ? a : gcd(b, a % b);
}

Fraction Reduction(Fraction result) {
if(result.down < 0) {
result.up = -result.up;
result.down = -result.down;
}
if(result.up == 0) {
result.down = 1;
} else {
long long d = gcd(abs(result.up), result.down);
result.up /= d;
result.down /= d;
}
return result;
}

Fraction Add(Fraction f1, Fraction f2) {
Fraction result;
result.up = f1.up * f2.down + f2.up * f1.down;
result.down = f1.down * f2.down;
return Reduction(result);
}

void printResult(Fraction result) {
Fraction r = Reduction(result);
if(r.down == 1) printf("%lld", r.up);
else if(abs(r.up) > r.down) {
printf("%lld %lld/%lld", r.up / r.down, abs(r.up) % r.down, r.down);
} else {
printf("%lld/%lld", r.up, r.down);
}
}

int main(int argc, char const *argv[]) {
int N;
scanf("%d", &N);
Fraction ans, temp;
ans.up = 0;
ans.down = 1;
while(N--) {
scanf("%lld/%lld", &temp.up, &temp.down);
ans = Add(ans, temp);
}
printResult(ans);
return 0;
}

贴个 C++ 版,把加法运算、化简和输出操作都封装起来:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include <iostream>
#include <algorithm>
using namespace std;
long long gcd(long long a, long long b) {
return b == 0 ? a : gcd(b, a % b);
}
struct Fraction {
long long up, down;
void reduction() {
if(this->down < 0) {
this->up = - this->up;
this->down = - this->down;
}
if(this->up == 0) this->down = 1;
else {
long long d = gcd(abs(this->up), this->down);
this->up /= d;
this->down /= d;
}
}
void Add(Fraction b) {
this->up = this->up * b.down + this->down * b.up;
this->down = this->down * b.down;
this->reduction();
}
void Print() {
if(this->down == 1) printf("%lld", this->up);
else if(abs(this->up) > this->down) {
printf("%lld %lld/%lld", this->up / this->down, abs(this->up) % this->down, this->down);
} else printf("%lld/%lld", this->up, this->down);
printf("\n");
}
};
int main() {
int n;
scanf("%d", &n);
Fraction ans, tmp;
ans.down = 1, ans.up = 0;
while(n--) {
scanf("%lld/%lld", &tmp.up, &tmp.down);
ans.Add(tmp);
}
ans.Print();
return 0;
}

1082 Read Number in Chinese

Analysis

将数字按每4位一组分割为不同的组,若是 9 位数,则有三组分别为:个位组、万位组和亿位组,然后针对每一组单独进行判断。对每一小组而言,要注意1001只能输出为yi Qian ling yi而不是yi Qian ling ling yi,即有累积的0时,只能输出一个ling

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include <cstdio>
#include <cstring>

char NumberTable[10][10] = { "ling", "yi", "er", "san", "si", "wu", "liu", "qi", "ba", "jiu", };
char Digit[5][10] = { "Shi", "Bai", "Qian", "Wan", "Yi", };

int main(int argc, char const *argv[]) {
char Num[15];
scanf("%s", Num);
int len = strlen(Num), left = 0, right = len - 1;
if(Num[0] == '-') {
printf("Fu");
left++;
}
while(left + 4 <= right) {
right -= 4;
}
while(left < len) {
bool flag = false, isPrint = false;
while(left <= right) {
if(left > 0 && Num[left] == '0') {
flag = true;
} else {
if(flag == true) {
printf(" ling");
flag = false;
}
if(left > 0) printf(" ");
printf("%s", NumberTable[Num[left] - '0']);
isPrint = true;
if(left != right) {
printf(" %s", Digit[right - left - 1]);
}
}
left++;
}
if(isPrint == true && right != len - 1) {
printf(" %s", Digit[(len - 1 - right) / 4 + 2]);
}
right += 4;
}
return 0;
}

1083 List Grades

Analysis

自定义结构体,输入数据后调用sort函数按照降序排序,然后根据题目给定的区间顺序输出符合这个区间内的元素即可。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include <cstdio>
#include <algorithm>
using namespace std;
const int MAXN = 100000 + 5;
struct student{
char name[15], id[15];
int grade;
} stu[MAXN];
bool cmp(student a, student b);

int main(int argc, char const *argv[]) {
int N, grade1, grade2;
scanf("%d", &N);
for(int i = 0; i < N; i++) {
scanf("%s %s %d", stu[i].name, stu[i].id, &stu[i].grade);
}
scanf("%d %d", &grade1, &grade2);
sort(stu, stu + N, cmp);
bool flag = false;
for(int i = 0; i < N; i++) {
if(grade1 <= stu[i].grade && stu[i].grade <= grade2) {
printf("%s %s\n", stu[i].name, stu[i].id);
flag = true;
}
}
if(!flag) {
printf("NONE\n");
}
return 0;
}

bool cmp(student a, student b) {
return a.grade > b.grade;
}

贴个 C++ 版:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 100000 + 5;
struct student {
string name, id;
int grade;
} stu[maxn];
int n;

int main() {
cin >> n;
for(int i = 0; i < n; i++) {
cin >> stu[i].name >> stu[i].id >> stu[i].grade;
}
sort(stu, stu + n, [](student a, student b) {
return a.grade > b.grade;
});
int left, right, cnt = 0;
cin >> left >> right;
for(int i = 0; i < n; i++) {
if(left <= stu[i].grade && stu[i].grade <= right) {
cout << stu[i].name << ' ' << stu[i].id << endl;
cnt++;
}
}
if(!cnt) cout << "NONE" << endl;
return 0;
}

1084 Broken Keyboard

Analysis

遍历字符串,找出第一个字符串中出现过,但第二个字符串中未出现的字符即可,字母不区分大小写,但字符串内有空格和数字,用_表示,注意不能输出小写字母,且重复的字符只输出一次。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <cstdio>
#include <cctype>

int main(int argc, char const *argv[]) {
char str1[85], str2[85];
scanf("%s %s", str1, str2);
bool HashTable[128] = {false};
for(int i = 0; str1[i] != '\0'; i++) {
int j = 0;
char c1 = str1[i];
for(; str2[j] != '\0'; j++) {
char c2 = str2[j];
if(islower(c1)) c1 = toupper(c1);
if(islower(c2)) c2 = toupper(c2);
if(c1 == c2) break;
}
if(str2[j] == '\0' && HashTable[c1] == false) {
printf("%c", c1);
HashTable[c1] = true;
}
}
putchar('\n');
return 0;
}

1085 Perfect Sequence

Analysis

此题与乙级题库的1030一样。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <cstdio>
#include <algorithm>
using namespace std;
const int MAXN = 100000 + 10;
long long n, p, Num[MAXN];
int BinarySearch(int i, long long x);

int main(int argc, char const *argv[]) {
scanf("%lld %lld", &n, &p);
for(int i = 0; i < n; i++) {
scanf("%lld", &Num[i]);
}
sort(Num, Num + n);
int ans = 1;
for(int i = 0; i < n; i++) {
int j = BinarySearch(i, Num[i] * p);
ans = max(ans, j - i);
}
printf("%d", ans);
return 0;
}

int BinarySearch(int i, long long x) {
if(Num[n - 1] <= x) {
return n;
}
int left = i + 1, right = n - 1, mid;
while(left < right) {
mid = (left + right) / 2;
if(Num[mid] <= x) {
left = mid + 1;
} else {
right = mid;
}
}
return left;
}

1086 Tree Traversals Again

Analysis

题目大意是给定用模拟二叉树中序遍历的入栈、出栈顺序,现在要求输出这个二叉树后序遍历序列。

根据题目给定的入栈、出栈序列,可以得到二叉树的先序遍历序列和后序遍历序列,根据这两个序列建树,然后再后序遍历这个二叉树即可。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#include <cstdio>
#include <stack>
#include <cstring>
using namespace std;
struct node {
int data;
node *lchild;
node *rchild;
};
int n, pre[50], in[50], order;
stack<int> st;
node *create(int preL, int preR, int inL, int inR) {
if(preL > preR) {
return NULL;
}
node *root = new node;
root->data = pre[preL];
int k;
for(k = inL; k <= inR; k++) {
if(in[k] == pre[preL]) {
break;
}
}
int numLeft = k - inL;
root->lchild = create(preL + 1, preL + numLeft, inL, k - 1);
root->rchild = create(preL + numLeft + 1, preR, k + 1, inR);
return root;
}
int num = 0;
void postorder(node *root) {
if(root == NULL) return;
postorder(root->lchild);
postorder(root->rchild);
printf("%d", root->data);
if(num < n - 1) {
printf(" ");
}
num++;
}

int main(int argc, char const *argv[]) {
scanf("%d", &n);
char str[5];
int x, preIndex = 0, inIndex = 0;
for(int i = 0; i < 2 * n; i++) {
scanf("%s", str);
if(strcmp("Push", str) == 0) {
scanf("%d", &x);
pre[preIndex++] = x;
st.push(x);
} else {
in[inIndex++] = st.top();
st.pop();
}
}
node *root = create(0, n - 1, 0, n - 1);
postorder(root);
return 0;
}

1087 All Roads Lead to Rome

Analysis

题目背景是旅游的路线图,要求按照条件求出最短路径及特定的值。

题目首先要求出的是从起点到终点的最短路径,由于不存在负环,所以可以直接使用 Dijkstra 算法求得;同时注意到,题目要求的某些特殊值与对应的路径可以在求解最短路时,一并求出,只不过需要使用多个数组而已。按照这样的思路,对题目要求的值增加对应的数组,并在求解最最短路的过程中写清楚这些条件之间的层次关系即可。

当然了,本题也可以使用 Dijkstra 算法先求出所有的最短路径,然后再利用 DFS 来求出符合条件的最优解和对应的值。

Code

Dijkstra

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
#include <iostream>
#include <string>
#include <map>
#include <cstring>
using namespace std;
const int maxv = 210;
const int inf = 0x3fffffff;
int n, k, G[maxv][maxv], weight[maxv];
int d[maxv], w[maxv] = {0}, num[maxv] = {0}, pt[maxv] = {0}, pre[maxv];
bool vis[maxv] = {false};
map<string, int> city2index;
map<int, string> index2city;
void dijkstra(int s) {
fill(d, d + maxv, inf);
d[s] = 0;
w[s] = weight[s];
num[s] = 1;
for(int i = 0; i < n; i++) {
int u = -1, min = inf;
for(int j = 0; j < n; j++) {
if(vis[j] == false && d[j] < min) {
min = d[j];
u = j;
}
}
if(u == -1) return;
vis[u] = true;
for(int v = 0; v < n; v++) {
if(vis[v] == false && G[u][v] != inf) {
if(d[v] > d[u] + G[u][v]) {
d[v] = d[u] + G[u][v];
pre[v] = u;
num[v] = num[u];
w[v] = w[u] + weight[v];
pt[v] = pt[u] + 1;
} else if(d[v] == d[u] + G[u][v]) {
num[v] += num[u];
if(w[v] < w[u] + weight[v]) {
w[v] = w[u] + weight[v];
pre[v] = u;
pt[v] = pt[u] + 1;
} else if(w[v] == w[u] + weight[v]) {
double uavg = 1.0 * (w[u] + weight[v]) / (pt[u] + 1);
double vavg = 1.0 * w[v] / pt[v];
if(uavg > vavg) {
pt[v] = pt[u] + 1;
pre[v] = u;
}
}
}
}
}
}
}
void dfs(int v) {
if(v == 0) {
cout << index2city[v];
return;
}
dfs(pre[v]);
cout << "->" << index2city[v];
}
int main(int argc, char const *argv[]) {
string city1, city2;
cin >> n >> k >> city1;
city2index[city1] = 0;
index2city[0] = city1;
for(int i = 1; i < n; i++) {
cin >> city1 >> weight[i];
city2index[city1] = i;
index2city[i] = city1;
}
fill(G[0], G[0] + maxv * maxv, inf);
int u, v, dis;
for(int i = 0; i < k; i++) {
cin >> city1 >> city2 >> dis;
u = city2index[city1], v = city2index[city2];
G[u][v] = G[v][u] = dis;
}
dijkstra(0);
int rom = city2index["ROM"];
cout << num[rom] << ' ' << d[rom] << ' ' << w[rom] << ' '
<< w[rom] / pt[rom] << endl;
dfs(rom);
return 0;
}

Dijkstra + DFS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
#include <iostream>
#include <vector>
#include <map>
#include <string>
#include <cstring>
using namespace std;
const int maxv = 210;
const int inf = 0x3fffffff;
int n, k, G[maxv][maxv], weight[maxv];
int d[maxv], numpath = 0, maxw = 0;
double maxavg = 0;
bool vis[maxv] = {false};
map<string, int> city2index;
map<int, string> index2city;
vector<int> pre[maxv], tempath, path;
void dijkstra(int s) {
fill(d, d + maxv, inf);
d[s] = 0;
for(int i = 0; i < n; i++) {
int u = -1, min = inf;
for(int j = 0; j < n; j++) {
if(vis[j] == false && d[j] < min) {
min = d[j];
u = j;
}
}
if(u == -1) return;
vis[u] = true;
for(int v = 0; v < n; v++) {
if(vis[v] == false && G[u][v] != inf) {
if(d[v] > d[u] + G[u][v]) {
d[v] = d[u] + G[u][v];
pre[v].clear();
pre[v].push_back(u);
} else if(d[v] == d[u] + G[u][v]) {
pre[v].push_back(u);
}
}
}
}
}
void dfs(int v) {
if(v == 0) {
tempath.push_back(v);
numpath++;
int tempw = 0;
for(int i = tempath.size() - 1; i >= 0; i--) {
int id = tempath[i];
tempw += weight[id];
}
double tempavg = 1.0 * tempw / (tempath.size() - 1);
if(tempw > maxw) {
maxw = tempw;
maxavg = tempavg;
path = tempath;
} else if(tempw == maxw && tempavg > maxavg) {
maxavg = tempavg;
path = tempath;
}
tempath.pop_back();
return;
}
tempath.push_back(v);
for(int i = 0; i < pre[v].size(); i++) {
dfs(pre[v][i]);
}
tempath.pop_back();
}
int main(int argc, char const *argv[]) {
string city1, city2;
cin >> n >> k >> city1;
city2index[city1] = 0;
index2city[0] = city1;
for(int i = 1; i < n; i++) {
cin >> city1 >> weight[i];
index2city[i] = city1;
city2index[city1] = i;
}
fill(G[0], G[0] + maxv * maxv, inf);
int u, v, dis;
for(int i = 0; i < k; i++) {
cin >> city1 >> city2 >> dis;
u = city2index[city1];
v = city2index[city2];
G[u][v] = G[v][u] = dis;
}
dijkstra(0);
int rom = city2index["ROM"];
dfs(rom);
cout << numpath << ' ' << d[rom] << ' ' << maxw << ' ' <<
(int)maxavg << endl;
for(int i = path.size() - 1; i >= 0; i--) {
cout << index2city[path[i]];
if(i > 0) cout << "->";
}
return 0;
}

1088 Rational Arithmetic

Analysis

此题与乙级题库的1034一样。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long ll;
ll gcd(ll a, ll b);
struct Fraction{
ll up, down;
} a, b;

Fraction Reduction(Fraction result) {
if(result.down < 0) {
result.up = -result.up;
result.down = -result.down;
}
if(result.up == 0) {
result.down = 1;
} else {
int d = gcd(abs(result.up), abs(result.down));
result.up /= d;
result.down /=d;
}
return result;
}

Fraction Add(Fraction f1, Fraction f2) {
Fraction result;
result.up = f1.up * f2.down + f2.up * f1.down;
result.down = f1.down * f2.down;
return Reduction(result);
}

Fraction Minu(Fraction f1, Fraction f2) {
Fraction result;
result.up = f1.up * f2.down - f2.up * f1.down;
result.down = f1.down * f2.down;
return Reduction(result);
}

Fraction Mult(Fraction f1, Fraction f2) {
Fraction result;
result.up = f1.up * f2.up;
result.down = f1.down * f2.down;
return Reduction(result);
}

Fraction Divide(Fraction f1, Fraction f2) {
Fraction result;
result.up = f1.up * f2.down;
result.down = f1.down * f2.up;
return Reduction(result);
}

void showResult(Fraction r) {
r = Reduction(r);
if(r.up < 0) printf("(");
if(r.down == 1) printf("%lld", r.up);
else if(abs(r.up) > r.down) {
printf("%lld %lld/%lld", r.up / r.down, abs(r.up) % r.down, r.down);
} else {
printf("%lld/%lld", r.up, r.down);
}
if(r.up < 0) printf(")");
}

int main(int argc, char const *argv[]) {
scanf("%lld/%lld %lld/%lld", &a.up, &a.down, &b.up, &b.down);
//add
showResult(a);
printf(" + ");
showResult(b);
printf(" = ");
showResult(Add(a, b));
putchar('\n');
//minu
showResult(a);
printf(" - ");
showResult(b);
printf(" = ");
showResult(Minu(a, b));
putchar('\n');
//mult
showResult(a);
printf(" * ");
showResult(b);
printf(" = ");
showResult(Mult(a, b));
putchar('\n');
//divide
showResult(a);
printf(" / ");
showResult(b);
printf(" = ");
if(b.up == 0) printf("Inf");
else showResult(Divide(a, b));

return 0;
}

ll gcd(ll a, ll b) {
return b == 0 ? a : gcd(b, a % b);
}

贴个 C++ 版,把基本运算全都封装起来:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
#include <iostream>
#include <algorithm>
using namespace std;
long long gcd(long long a, long long b) {
return b == 0 ? a : gcd(b, a % b);
}
struct Fraction {
long long up, down;
void reduction() {
if(this->down < 0) {
this->up = - this->up;
this->down = - this->down;
}
if(this->up == 0) this->down = 1;
else {
long long d = gcd(abs(this->up), this->down);
this->up /= d;
this->down /= d;
}
}
void Add(Fraction b) {
this->up = this->up * b.down + this->down * b.up;
this->down = this->down * b.down;
this->reduction();
}
void Minu(Fraction b) {
this->up = this->up * b.down - this->down * b.up;
this->down = this->down * b.down;
this->reduction();
}
void Mult(Fraction b) {
this->up = this->up * b.up;
this->down = this->down * b.down;
this->reduction();
}
void Div(Fraction b) {
this->up = this->up * b.down;
this->down = this->down * b.up;
this->reduction();
}
void printResult() {
this->reduction();
if(this->up < 0) printf("(");
if(this->down == 1) printf("%lld", this->up);
else if(abs(this->up) > this->down) {
printf("%lld %lld/%lld", this->up / this->down, abs(this->up) % this->down, this->down);
} else {
printf("%lld/%lld", this->up, this->down);
}
if(this->up < 0) printf(")");
}
};
int main() {
Fraction res, a, b;
scanf("%lld/%lld %lld/%lld", &a.up, &a.down, &b.up, &b.down);
res = a;
a.printResult();
printf(" + ");
b.printResult();
printf(" = ");
res.Add(b);
res.printResult();
printf("\n");
res = a;
a.printResult();
printf(" - ");
b.printResult();
printf(" = ");
res.Minu(b);
res.printResult();
printf("\n");
res = a;
a.printResult();
printf(" * ");
b.printResult();
printf(" = ");
res.Mult(b);
res.printResult();
printf("\n");
res = a;
a.printResult();
printf(" / ");
b.printResult();
printf(" = ");
if(b.up == 0) printf("Inf");
else {
res.Div(b);
res.printResult();
}
printf("\n");
return 0;
}

1089 Insert or Merge

Analysis

此题与乙级题库的1035一样。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
#include <cstdio>
#include <algorithm>
using namespace std;
const int MAXN = 100 + 10;
int ori[MAXN], tempOri[MAXN], changed[MAXN];
int n;

bool isSame(int A[], int B[]) {
for(int i = 0; i < n; i++) {
if(A[i] != B[i]) return false;
}
return true;
}

void showArray(int A[]) {
for(int i = 0; i < n; i++) {
printf("%d", A[i]);
if(i < n - 1) putchar(' ');
}
}

bool InsertionSort() {
bool flag = false;
for(int i = 1; i < n; i++) {
if(i != 1 && isSame(tempOri, changed)) {
flag = true;
}
int temp = tempOri[i], j = i;
while(j > 0 && tempOri[j - 1] > temp) {
tempOri[j] = tempOri[j - 1];
j--;
}
tempOri[j] = temp;
if(flag) {
return true;
}
}
return false;
}

void MergeSort() {
bool flag = false;
for(int step = 2; step / 2 <= n; step *= 2) {
if(step != 2 && isSame(tempOri, changed)) {
flag = true;
}
for(int i = 0; i < n; i += step) {
sort(tempOri + i, tempOri + min(i + step, n));
}
if(flag) {
showArray(tempOri);
return;
}
}
}

int main(int argc, char const *argv[]) {
scanf("%d", &n);
for(int i = 0; i < n; i++) {
scanf("%d", &ori[i]);
tempOri[i] = ori[i];
}
for(int i = 0; i < n; i++) {
scanf("%d", &changed[i]);
}
if(InsertionSort()) {
printf("Insertion Sort\n");
showArray(tempOri);
} else {
printf("Merge Sort\n");
for(int i = 0; i < n; i++) {
tempOri[i] = ori[i];
}
MergeSort();
}
return 0;
}

1090 Highest Price in Supply Chain

Analysis

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include <cstdio>
#include <cmath>
#include <vector>
using namespace std;
const int maxn = 100005;
struct node {
double data;
vector<int> child;
} Node[maxn];
int n, num = 0;
double p, r, maxDepth = 0;
void DFS(int index, int depth) {
if(Node[index].child.size() == 0) {
if(depth > maxDepth) {
maxDepth = depth;
num = 1;
} else if(depth == maxDepth) {
num++;
}
return;
}
for(int i = 0; i < Node[index].child.size(); i++) {
DFS(Node[index].child[i], depth + 1);
}
}

int main(int argc, char const *argv[]) {
scanf("%d %lf %lf", &n, &p, &r);
r /= 100;
int root, parent;
for(int i = 0; i < n; i++) {
scanf("%d", &parent);
if(parent != -1) {
Node[parent].child.push_back(i);
} else {
root = i;
}
}
DFS(root, 0);
printf("%.2lf %d\n", p * pow(1 + r, maxDepth), num);
return 0;
}

1091 Acute Stroke

Analysis

题目的背景大概是计算体积之和吧...

根据题目输入数据的形式和题目大意,思路是借助 BFS 对三维数组进行遍历,计算出每一个薄片(slice)中为“1”的个数,如果大于题目给定的T,则当前这个薄片内“1”的个数就可以认为是这个薄片的“急性脑卒中”区的体积。那么,依次遍历每个薄片即可得到最终结果。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
#include <cstdio>
#include <queue>
using namespace std;
struct node {
int x, y, z;
} Node;
int n, m, slice, T;
int pixel[1290][130][61];
bool inqueue[1290][130][61];
int X[6] = {0, 0, 0, 0, 1, -1};
int Y[6] = {0, 0, 1, -1, 0, 0};
int Z[6] = {1, -1, 0, 0, 0, 0};

bool judge(int x, int y, int z) {
if(x >= n || x < 0 || y >= m || y < 0 || z >= slice || z < 0) return false;
if(pixel[x][y][z] == 0 || inqueue[x][y][z] == true) return false;
return true;
}

int BFS(int x, int y, int z) {
int tot = 0;
queue<node> Q;
Node.x = x, Node.y = y, Node.z = z;
Q.push(Node);
inqueue[x][y][z] = true;
while(!Q.empty()) {
node top = Q.front();
Q.pop();
tot++;
for(int i = 0; i < 6; i++) {
int newX = top.x + X[i];
int newY = top.y + Y[i];
int newZ = top.z + Z[i];
if(judge(newX, newY, newZ)) {
Node.x = newX, Node.y = newY, Node.z = newZ;
Q.push(Node);
inqueue[newX][newY][newZ] = true;
}
}
}
if(tot >= T) return tot;
else return 0;
}

int main(int argc, char const *argv[]) {
scanf("%d %d %d %d", &n, &m, &slice, &T);
for(int z = 0; z < slice; z++) {
for(int x = 0; x < n; x++) {
for(int y = 0; y < m; y++) {
scanf("%d", &pixel[x][y][z]);
}
}
}
int ans = 0;
for(int z = 0; z < slice; z++) {
for(int x = 0; x < n; x++) {
for(int y = 0; y < m; y++) {
if(pixel[x][y][z] == 1 && inqueue[x][y][z] == false) {
ans += BFS(x, y, z);
}
}
}
}
printf("%d", ans);
return 0;
}

1092 To Buy or Not to Buy

Analysis

与乙级题库的1039一样。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <cstdio>
#include <cstring>
const int MAXN = 1000 + 5;

void get_count(int *a, char *s);

int main(int argc, char const *argv[]) {
char str1[MAXN], str2[MAXN];
fgets(str1, MAXN, stdin);
fgets(str2, MAXN, stdin);
int count1[90] = {0}, count2[90] = {0};
get_count(count1, str1);
get_count(count2, str2);
int temp, less = 0, len1 = strlen(str1), len2 = strlen(str2);
bool enough = true;
for(int i = 0; i < 90; i++) {
temp = count2[i] - count1[i];
if(temp > 0) {
less += temp;
enough = false;
}
}
if(enough) {
printf("Yes %d\n", len1 - len2);
} else {
printf("No %d\n", less);
}
return 0;
}

void get_count(int *a, char *s) {
char *p = s;
while(*p != '\0') {
a[*p - '0']++;
p++;
}
}

1093 Count PAT’s

Analysis

与乙级题库的1040一样。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <cstdio>
#include <cstring>
const int MAXN = 100000 + 10;
const int MOD = 1000000007;
char str[MAXN];
int leftNumP[MAXN] = {0};

int main(int argc, char const *argv[]) {
scanf("%s", str);
int len = strlen(str);
for(int i = 0; i < len; i++) {
if(i > 0) {
leftNumP[i] = leftNumP[i - 1];
}
if(str[i] == 'P') leftNumP[i]++;
}
int ans = 0, rightNumT = 0;
for(int i = len - 1; i > 0; i--) {
if(str[i] == 'T') {
rightNumT++;
} else if(str[i] == 'A') {
ans = (ans + leftNumP[i] * rightNumT) % MOD;
}
}
printf("%d", ans);
return 0;
}

贴个 C++ 版:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>
using namespace std;

int main() {
string str;
cin >> str;
int pcnt = 0, tcnt = 0;
for(char &ch: str) {
if(ch == 'T') tcnt++;
}
int ans = 0;
for(char &ch: str) {
if(ch == 'A') {
ans += tcnt * pcnt;
ans %= 1000000007;
} else if(ch == 'P') pcnt++;
else tcnt--;
}
cout << ans;
return 0;
}

1094 The Largest Generation

Analysis

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#include <iostream>
#include <queue>
using namespace std;
const int maxn = 110;
struct node {
int depth;
vector<int> child;
} Node[maxn];
int n, m, seq, child;
int Depth[maxn] = {0};
void BFS() {
queue<int> q;
q.push(1);
Node[1].depth = 1;
Depth[Node[1].depth]++;
while(!q.empty()) {
int front = q.front();
q.pop();
for(int i = 0; i < Node[front].child.size(); i++) {
int child = Node[front].child[i];
Node[child].depth = Node[front].depth + 1;
Depth[Node[child].depth]++;
q.push(child);
}
}
}

int main(int argc, char const *argv[]) {
cin >> n >> m;
int k;
for(int i = 0; i < m; i++) {
cin >> seq >> k;
for(int j = 0; j < k; j++) {
cin >> child;
Node[seq].child.push_back(child);
}
}
BFS();
int max = -1, l = 1;
for(int i = 0; i < maxn; i++) {
if(Depth[i] > max) {
max = Depth[i];
l = i;
}
}
cout << Depth[l] << ' ' << l << endl;
return 0;
}

1095 Cars on Campus

Analysis

这又是一道相当麻烦的排序题,和 1016 很像,有些地方又比 1016 简单一点。
首先要注意的事情是,如何把题目的一些条件简化,比如时间全部简化成秒,这样排序时就可以直接按照秒数的大小进行排序了。不过,对于这个题而言,第一排序依据是plate_number,然后才是时间。排序完成后,需要将所有合法的记录对挑出来,作为后面查询每个时间内停车场内车辆数据的依据,也就是相邻的两个记录组成一对,plate_number相同,一个是in,另外一个是out
此时,可以顺便把每辆车的停车时间和最长的停车时间算出来,每辆车的停车时间可以借助 map 来统计。
接着就是查询的过程,因为题目规定了给定的查询时间是从小到大的。所以,在查询前,先对合法记录按时间排序。然后,设置一个变量 now,从头开始进行遍历,遇到in的记录,当前车辆数就加 1,遇到out的记录,就减一,这样就只用遍历一次所有的合法记录。
最后就是输出停车时间与最长停车时间相等的车牌号和总时间了。
两个字:麻烦~🙃

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#include <cstdio>
#include <cstring>
#include <string>
#include <map>
#include <algorithm>
using namespace std;
const int maxn = 10000 + 10;
struct car {
char pnum[8], status[5];
int time;
} all[maxn], valid[maxn];
int n, k, validcnt = 0;
map<string, int> parktime;
bool cmpbypnumandtime(car a, car b) {
if(strcmp(a.pnum, b.pnum) != 0) return strcmp(a.pnum, b.pnum) < 0;
else return a.time < b.time;
}
bool cmpbytime(car a, car b) {
return a.time < b.time;
}
int time2int(int hh, int mm, int ss) {
return hh * 3600 + mm * 60 + ss;
}
int main() {
scanf("%d %d", &n, &k);
int hh, mm, ss;
for(int i = 0; i < n; i++) {
scanf("%s %d:%d:%d %s", all[i].pnum, &hh, &mm, &ss, all[i].status);
all[i].time = time2int(hh, mm, ss);
}
sort(all, all + n, cmpbypnumandtime);
int maxtime = -1;
for(int i = 0; i < n - 1; i++) {
if(!strcmp(all[i].pnum, all[i + 1].pnum) &&
!strcmp(all[i].status, "in") &&
!strcmp(all[i + 1].status, "out")) {
valid[validcnt++] = all[i];
valid[validcnt++] = all[i + 1];
int intime = all[i + 1].time - all[i].time;
if(parktime.count(all[i].pnum) == 0) {
parktime[all[i].pnum] = 0;
}
parktime[all[i].pnum] += intime;
maxtime = max(maxtime, parktime[all[i].pnum]);
}
}
sort(valid, valid + validcnt, cmpbytime);
int now = 0, numcar = 0;
for(int i = 0; i < k; i++) {
scanf("%d:%d:%d", &hh, &mm, &ss);
int time = time2int(hh, mm, ss);
while(now < validcnt && valid[now].time <= time) {
if(!strcmp(valid[now].status, "in")) numcar++;
else numcar--;
now++;
}
printf("%d\n", numcar);
}
for(auto it = parktime.begin(); it != parktime.end(); it++) {
if(it->second == maxtime) printf("%s ", it->first.c_str());
}
printf("%02d:%02d:%02d", maxtime / 3600, maxtime % 3600 / 60, maxtime % 60);
return 0;
}

1096 Consecutive Factors

Analysis

题目大意是给定一个整数,找出其最长的因子序列并要求连续因子尽可能小,以样例为例,630=3*5*6*7,所以其连续因子序列为5*6*7,长度为 3 且此为其最长连续因子序列。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;
typedef long long ll;
int main(int argc, char const *argv[]) {
ll n;
scanf("%lld", &n);
ll sqr = sqrt(n), ansI = 0, ansLen = 0;
for(ll i = 2; i <= sqr; i++) {
ll temp = 1, j = i;
while(1) {
temp *= j;
if(n % temp != 0) break;
if(j - i + 1 > ansLen) {
ansI = i;
ansLen = j - i + 1;
}
j++;
}
}
if(ansLen == 0) {
printf("1\n%lld\n", n);
} else {
printf("%lld\n", ansLen);
for(ll i = 0; i < ansLen; i++) {
printf("%lld", ansI + i);
if(i < ansLen - 1) putchar('*');
}
}
return 0;
}

贴个 C++ 暴力模拟的解法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <iostream>
#include <cmath>
#include <vector>
using namespace std;

int main() {
int n;
cin >> n;
int anslen = 0;
vector<int> ans;
for(int i = 2; i <= sqrt(n); i++) {
int len = 0, j = i;
long long t = 1;
vector<int> tmp;
while(true) {
tmp.push_back(j);
t *= j;
if(n % t == 0) len++;
else break;
if(len > anslen) {
anslen = len;
ans = tmp;
}
j++;
}
}
if(anslen == 0) cout << 1 << endl << n;
else {
cout << anslen << endl;
for(int i = 0; i < anslen; i++) {
cout << ans[i];
if(i < anslen - 1) cout << '*';
}
}
return 0;
}

因为是从小到大枚举因子的,所以如果是符合条件的最终解,那么一定满足因子是最小的。实际上,这个题还可以从滑动窗口的角度来思考。

1097 Deduplication on a Linked List

Analysis

题目大意:给定一串链表的各个结点,删除其中重复的结点,并将删除的结点重新组成一个链表。然后,先输出原链表删除结点后的新链表,紧接着在输出由所删除的结点构成的链表。

使用静态链表来处理这个问题,先默认初始化链表内的所有结点全部为无效结点,即置为2 * maxn,然后将链表内所有结点根据地址存储。紧接着,遍历链表,使用一个bool数组来记录结点是否出现过,对于没有出现的合法结点,从0开始编号,出现过的结点,从maxn开始编号。最后,使用sort函数根据order来排序,就可以将结点按序分为删除结点后的链表、新链表和无效结点三部分,在输出即可。

注意要使用%05d来输出地址位数较少的结点。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std;
const int maxn = 100005;
const int Table = 2 * maxn;
struct node{
int address, next, key;
int order;
} Node[maxn];
bool isExist[Table] = {false};
bool cmp(node a, node b) {
return a.order < b.order;
}
int main(int argc, char const *argv[]) {
for(int i = 0; i < maxn; i++) {
Node[i].order = 2 * maxn;
}
int n, head, address;
scanf("%d %d", &head, &n);
for(int i = 0; i < n; i++) {
scanf("%d", &address);
scanf("%d %d", &Node[address].key, &Node[address].next);
Node[address].address = address;
}
int countValid = 0, countRemoved = 0, p = head;
while(p != -1) {
if(!isExist[abs(Node[p].key)]) {
isExist[abs(Node[p].key)] = true;
Node[p].order = countValid++;
} else {
Node[p].order = maxn + countRemoved++;
}
p = Node[p].next;
}
sort(Node, Node + maxn, cmp);
int count = countValid + countRemoved;
for(int i = 0; i < count; i++) {
if(i != countValid - 1 && i != count - 1) {
printf("%05d %d %05d\n", Node[i].address, Node[i].key,
Node[i + 1].address);
} else {
printf("%05d %d -1\n", Node[i].address, Node[i].key);
}
}
return 0;
}

1098 Insertion or Heap Sort

Analysis

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn = 110;
int origin[maxn], tempori[maxn], changed[maxn];
int n;
bool isSame(int A[], int B[]) {
for(int i = 1; i <= n; i++) {
if(A[i] != B[i]) return false;
}
return true;
}
bool showArray(int A[]) {
for(int i = 1; i <= n; i++) {
printf("%d", A[i]);
if(i < n) putchar(' ');
}
putchar('\n');
}
bool insertSort() {
bool flag = false;
for(int i = 2; i <= n; i++) {
if(i != 2 && isSame(tempori, changed)) {
flag = true;
}
sort(tempori, tempori + i + 1);
if(flag == true) {
return true;
}
}
return false;
}
void downAdjust(int low, int high) {
int i = low, j = 2 * i;
while(j <= high) {
if(j + 1 <= high && tempori[j + 1] > tempori[j]) {
j = j + 1;
}
if(tempori[j] > tempori[i]) {
swap(tempori[j], tempori[i]);
i = j;
j = i * 2;
} else {
break;
}
}
}
void heapSort() {
bool flag = false;
for(int i = n / 2; i >= 1; i--) {
downAdjust(i, n);
}
for(int i = n; i > 1; i--) {
if(i != n && isSame(tempori, changed)) {
flag = true;
}
swap(tempori[i], tempori[1]);
downAdjust(1, i - 1);
if(flag == true) {
showArray(tempori);
return;
}
}
}
int main(int argc, char const *argv[]) {
scanf("%d", &n);
for(int i = 1; i <= n; i++) {
scanf("%d", &origin[i]);
tempori[i] = origin[i];
}
for(int i = 1; i <= n; i++) {
scanf("%d", &changed[i]);
}
if(insertSort()) {
printf("Insertion Sort\n");
showArray(tempori);
} else {
printf("Heap Sort\n");
for(int i = 1; i <= n; i++) {
tempori[i] = origin[i];
}
heapSort();
}

return 0;
}

1099 Build A Binary Search Tree

Analysis

题目大意给定一颗二叉排序树(BST),输出这棵树的层次序列。

根据题目输入数据的形式,利用结构数组建树比较方便。建树之后,中序遍历这棵树,将按升序排好的结点值序列,按照顺序赋给每个结点,这样每个结点的值就符合 BST 的性质了,接着层次遍历,输出其序列即可。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include <iostream>
#include <queue>
#include <algorithm>
using namespace std;
const int maxn = 110;
struct node {
int data;
int left, right;
} Node[maxn];
int n, number[maxn], index = 0;

void inorder(int root) {
if(root == -1) return;
inorder(Node[root].left);
Node[root].data = number[index++];
inorder(Node[root].right);
}
int num = 0;
void levelorder(int root) {
if(root == -1) return;
queue<int> q;
q.push(root);
while(!q.empty()) {
int front = q.front();
q.pop();
cout << Node[front].data;
if(num < n - 1) {
cout << ' ';
num++;
}
if(Node[front].left != -1) q.push(Node[front].left);
if(Node[front].right != -1) q.push(Node[front].right);
}
}

int main(int argc, char const *argv[]) {
cin >> n;
int lchild, rchild;
for(int i = 0; i < n; i++) {
cin >> lchild >> rchild;
Node[i].left = lchild, Node[i].right = rchild;
}
for(int i = 0; i < n; i++) {
cin >> number[i];
}
sort(number, number + n);
inorder(0);
levelorder(0);
return 0;
}

1100 Mars Numbers

Analysis

此题与乙级题库的1044一样。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include <iostream>
#include <string>
#include <map>
using namespace std;
string unitDigit[13] = {"tret", "jan", "feb", "mar", "apr", "may", "jun",
"jly", "aug", "sep", "oct", "nov", "dec",
};
string tenDigit[13] = {"tret", "tam", "hel", "maa", "huh", "tou", "kes",
"hei", "elo", "syy", "lok", "mer", "jou",
};
string numToStr[170];
map<string, int> strToNum;
void init();
int main(int argc, char const*argv[]) {
init();
int n;
cin >> n;
getchar();
string s;
while(n--) {
string str;
getline(cin, str);
if('0' <= str[0] && str[0] <= '9') {
int num = 0;
for(int i = 0; i < str.length(); i++) {
num = num * 10 + (str[i] - '0');
}
cout << numToStr[num] << endl;
} else {
cout << strToNum[str] << endl;
}
}
return 0;
}

void init() {
for(int i = 0; i < 13; i++) {
numToStr[i] = unitDigit[i];
strToNum[unitDigit[i]] = i;
numToStr[i * 13] = tenDigit[i];
strToNum[tenDigit[i]] = i * 13;
}
for(int i = 1; i < 13; i++) {
for(int j = 1; j < 13; j++) {
string str = tenDigit[i] + ' ' + unitDigit[j];
numToStr[i * 13 + j] = str;
strToNum[str] = i * 13 + j;
}
}
}

1101 Quick Sort

Analysis

此题与乙级题库的1045一样。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <cstdio>
#include <algorithm>
using namespace std;
const int MAXN = 100000 + 10;
int n, array[MAXN], leftmax[MAXN], rightmin[MAXN], pivot[MAXN];

int main(int argc, char const *argv[]) {
scanf("%d", &n);
for(int i = 0; i < n; i++) {
scanf("%d", &array[i]);
}
leftmax[0] = array[0];
for(int i = 1; i < n; i++) {
leftmax[i] = max(leftmax[i - 1], array[i - 1]);
}
rightmin[n - 1] = 0x3fffffff;
for(int i = n - 2; i >= 0; i--) {
rightmin[i] = min(rightmin[i + 1], array[i + 1]);
}
int count = 0;
for(int i = 0; i < n; i++) {
if(leftmax[i] <= array[i] && array[i] <= rightmin[i]) {
pivot[count++] = array[i];
}
}
printf("%d\n", count);
for(int i = 0; i < count; i++) {
printf("%d", pivot[i]);
if(i < count - 1) putchar(' ');
}
putchar('\n');
return 0;
}

1102 Invert a Binary Tree

Analysis

题目大意是给定一个二叉树,反转这个二叉树并输出反转后的二叉树的中序序列和层序序列。

本题使用结构数组建树比较方便,并且反转时直接交换每个结点的左右孩子指针即可。然后再利用中序遍历和层序遍历,输出对应的序列。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
#include <cstdio>
#include <queue>
#include <algorithm>
using namespace std;
struct node {
int data;
int lchild, rchild;
} Node[15];
int n;
bool isRoot[15] = {false};
int num = 0;
void levelorder(int root) {
if(root == -1) return;
queue<node> q;
q.push(Node[root]);
while(!q.empty()) {
node top = q.front();
q.pop();
printf("%d", top.data);
if(num < n - 1) {
printf(" ");
num++;
}
if(top.lchild != -1) q.push(Node[top.lchild]);
if(top.rchild != -1) q.push(Node[top.rchild]);
}
putchar('\n');
}
int num2 = 0;
void inorder(int root) {
if(root == -1) return;
inorder(Node[root].lchild);
printf("%d", Node[root].data);
if(num2 < n - 1) {
printf(" ");
num2++;
}
inorder(Node[root].rchild);
}
int getroot() {
int ret = 0;
for(int i = 0; i < n; i++) {
if(!isRoot[i]) {
ret = i;
break;
}
}
return ret;
}

void invert() {
int i = 0;
for(int i = 0; i < n; i++) {
swap(Node[i].lchild, Node[i].rchild);
}
}

int main(int argc, char const *argv[]) {
scanf("%d", &n);
getchar();
char left, right;
for(int i = 0; i < n; i++) {
scanf("%c %c", &left, &right);
getchar();
if(left != '-') {
Node[i].lchild = left - '0';
isRoot[left - '0'] = true;
}
else Node[i].lchild = -1;
if(right != '-') {
Node[i].rchild = right - '0';
isRoot[right - '0'] = true;
}
else Node[i].rchild = -1;
Node[i].data = i;
}
int root = getroot();
invert();
levelorder(root);
inorder(root);
return 0;
}

1103 Integer Factorization

Analysis

题目大意,给定三个数NKP,将N表示为K个因子的P次方的连加。
注意题目的要求:

  1. 因子之和必须最大
  2. 因子序列按字典序最大

由于存在多解的情况,本题需要借助 DFS 来搜索所有解,找到符合条件的最优解,对于上述两个题目的要求,其对应的解决方法:

  1. 使用全局变量,记录每个解和其因子和,选择因子和最大的为最优解
  2. 将因子的P次方依次算好存储在数组中,然后从后往前枚举即可

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
int n, k, p, maxFacsum = -1;
vector<int> fac, ans, temp;

int power(int x) {
int ret = 1;
for(int i = 0; i < p; i++) {
ret *= x;
}
return ret;
}

void init() {
int i = 0, temp = 0;
while(temp <= n) {
fac.push_back(temp);
temp = power(++i);
}
}

void DFS(int index, int nowK, int sum, int facSum) {
if(sum == n && nowK == k) {
if(facSum > maxFacsum) {
ans = temp;
maxFacsum = facSum;
}
return;
}
if(sum > n || nowK > k) return;
if(index - 1 >= 0) {
temp.push_back(index);
DFS(index, nowK + 1, sum + fac[index], facSum + index);
temp.pop_back();
DFS(index - 1, nowK, sum, facSum);
}
}

int main(int argc, char const *argv[]) {
scanf("%d %d %d", &n, &k, &p);
init();
DFS(fac.size() - 1, 0, 0, 0);
if(maxFacsum == -1) {
printf("Impossible\n");
} else {
printf("%d = %d^%d", n, ans[0], p);
for(int i = 1; i < ans.size(); i++) {
printf(" + %d^%d", ans[i], p);
}
}
return 0;
}

1104 Sum of Number Segments

Analysis

此题与乙级题库的1049一样。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <cstdio>
const int MAXN = 100000 + 10;
double seq[MAXN] = {0};

int main(int argc, char const *argv[]) {
int n;
scanf("%d", &n);
for(int i = 0; i < n; i++) {
scanf("%lf", &seq[i]);
}
double ans = 0;
int i = 0;
ans = seq[0] * n;
if(n > 1) {
for(i = 1; i < n - 1; i++) {
ans += (seq[i] * (i + 1) * (n - i));
}
ans += seq[n - 1] * n;
}
printf("%.2lf\n", ans);
return 0;
}

1106 Lowest Price in Supply Chain

Analysis

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include <cstdio>
#include <cmath>
#include <vector>
using namespace std;
const int maxn = 100005;
vector<int> child[maxn];
int tot = 0, n, minDepth = maxn;
double p, r;
void DFS(int index, int depth) {
if(child[index].size() == 0) {
if(depth < minDepth) {
minDepth = depth;
tot = 1;
} else if(depth == minDepth) {
tot++;
}
return;
}
for(int i = 0; i < child[index].size(); i++) {
DFS(child[index][i], depth + 1);
}
}

int main(int argc, char const *argv[]) {
scanf("%d %lf %lf", &n, &p, &r);
r /= 100.0;
int num, subchild;
for(int i = 0; i < n; i++) {
scanf("%d", &num);
for(int j = 0; j < num; j++) {
scanf("%d", &subchild);
child[i].push_back(subchild);
}
}
DFS(0, 0);
double ans = p * pow(1 + r, minDepth);
printf("%.4lf %d", ans, tot);
return 0;
}

1107 Social Clusters

Analysis

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn = 1010;
int father[maxn], isroot[maxn] = {0}, hobby[maxn] = {0};
int findFather(int x) {
int a = x;
while(x != father[x]) {
x = father[x];
}
while(a != father[a]) {
int z = a;
a = father[a];
father[z] = x;
}
return x;
}
void Union(int a, int b) {
int faA = findFather(a);
int faB = findFather(b);
if(faA != faB) {
father[faA] = father[faB];
}
}
void init(int n) {
for(int i = 1; i <= n; i++) {
father[i] = i;
}
}
bool cmp(int a, int b) {
return a > b;
}
int main(int argc, char const *argv[]) {
int n, k, h;
scanf("%d", &n);
init(n);
for(int i = 1; i <= n; i++) {
scanf("%d:", &k);
for(int j = 0; j < k; j++) {
scanf("%d", &h);
if(hobby[h] == 0) {
hobby[h] = i;
}
Union(i, hobby[h]);
}
}
for(int i = 1; i <= n; i++) {
isroot[findFather(i)]++;
}
int ans = 0;
for(int i = 1; i <= n; i++) {
if(isroot[i] != 0) {
ans++;
}
}
printf("%d\n", ans);
sort(isroot + 1, isroot + n + 1, cmp);
for(int i = 1; i <= ans; i++) {
printf("%d", isroot[i]);
if(i < ans) putchar(' ');
}
return 0;
}

Buy me a coffee ? :)
0%