UVa 1494 - Qin Shi Huang's National Road System

Problem

During the Warring States Period of ancient China(476 BC to 221 BC), there were seven kingdoms in China – they were Qi, Chu, Yan, Han, Zhao, Wei and Qin. Ying Zheng was the king of the kingdom Qin. Through 9 years of wars, he finally conquered all six other kingdoms and became the first emperor of a unified China in 221 BC. That was Qin dynasty – the first imperial dynasty of China(not to be confused with the Qing Dynasty, the last dynasty of China). So Ying Zheng named himself “Qin Shi Huang” because “Shi Huang” means “the first emperor “ in Chinese.

\epsfbox{p5713.eps}

Qin Shi Huang undertook gigantic projects, including the first version of the Great Wall of China, the now famous city-sized mausoleum guarded by a life-sized Terracotta Army, and a massive national road system. There is a story about the road system:

There were n cities in China and Qin Shi Huang wanted them all be connected by n - 1 roads, in order that he could go to every city from the capital city Xianyang. Although Qin Shi Huang was a tyrant, he wanted the total length of all roads to be minimum,so that the road system may not cost too many people’s life. A daoshi (some kind of monk) named Xu Fu told Qin Shi Huang that he could build a road by magic and that magic road would cost no money and no labor. But Xu Fu could only build ONE magic road for Qin Shi Huang. So Qin Shi Huang had to decide where to build the magic road. Qin Shi Huang wanted the total length of all none magic roads to be as small as possible, but Xu Fu wanted the magic road to benefit as many people as possible – So Qin Shi Huang decided that the value of A/B (the ratio of A to B) must be the maximum, which A is the total population of the two cites connected by the magic road, and B is the total length of none magic roads.

Would you help Qin Shi Huang?

A city can be considered as a point, and a road can be considered as a line segment connecting two points.

Input

The first line contains an integer t meaning that there are t test cases (t < 10).

For each test case:

The first line is an integer n meaning that there are n cities (2 < n <= 1000).

Then n lines follow. Each line contains three integers X, Y and P (0 < X, Y <= 1000, 0 < P < 100000). (X, Y) is the coordinate of a city and P is the population of that city.

It is guaranteed that each city has a distinct location.

Output

For each test case, print a line indicating the above mentioned maximum ratio A/B. The result should be rounded to 2 digits after decimal point.

Sample Input

1
2
3
4
5
6
7
8
9
10
2
4
1 1 20
1 2 30
200 2 80
200 1 100
3
1 1 20
1 2 30
2 2 40

Sample Output

1
2
65.00
70.00

Solution

題目描述:

有 n 個城市,在中國秦始皇希望他們都用連接 n - 1 道路,以便他可以去到每一個城市從首都咸陽。儘管秦始皇是個暴君,他希望所有的道路是最低的總長度,從而使道路系統可能不會花費太多勞力。倒是一個(一些和尚)命名徐福告訴秦始皇,他可以通過魔法修路和魔法的道路將花費沒用錢,沒用勞動力。但徐福只能建一個神奇的道路秦始皇。所以,秦始皇不得不決定在哪裡建造魔法的道路。秦始皇想所有無魔法的道路是盡可能小的總長度,但徐福希望魔法道路可以效益為盡可能多的人。所以秦始皇決定 A / B 必須是最大的,其中 A 是魔法路兩端的總人口,而 B 是沒有魔法的道路的總長度。

題目解法:

找出 MST,窮舉所有所有魔法路的可能。

對於一個 MST 修改一條邊,可在 O(n) 時間內找到環,之後將環上最重的邊去除即可。
但是這題中,MST 會保留住,因此對 MST 任兩點路徑上的最重邊進行在 O(n^2) 內完成計算。

  • MST 加入新點,可以在 O(n) 時間內完成 ?
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
#include <stdio.h>
#include <stdlib.h>
#include <algorithm>
#include <string.h>
#include <math.h>
#include <vector>
using namespace std;
struct E {
int x, y, v;
E(int a=0, int b=0, int c=0):
x(a), y(b), v(c) {}
bool operator<(const E &a) const {
return v < a.v;
}
};
E D[1000005];
vector<E> tree[1005];
int p[1005], rank[1005];
int findp(int x) {
return p[x] == x ? x : (p[x] = findp(p[x]));
}
int joint(int x, int y) {
x = findp(x), y = findp(y);
if(x == y)
return 0;
if(rank[x] > rank[y])
rank[x] += rank[y], p[y] = x;
else
rank[y] += rank[x], p[x] = y;
return 1;
}
double kruscal(int n, int m) {
double sum = 0;
sort(D, D+m);
for(int i = 0; i < n; i++) {
p[i] = i, rank[i] = 1;
tree[i].clear();
}
for(int i = 0; i < m; i++) {
if(joint(D[i].x, D[i].y)) {
sum += sqrt(D[i].v);
tree[D[i].x].push_back(E(D[i].x, D[i].y, D[i].v));
tree[D[i].y].push_back(E(D[i].y, D[i].x, D[i].v));
}
}
return sum;
}
int visited[1005];
double maxEdge[1005][1005];
void dfs(int u, int n) {
visited[u] = 1;
for(int i = 0; i < tree[u].size(); i++) {
int v = tree[u][i].y;
if(visited[v]) continue;
double cost = sqrt(tree[u][i].v);
maxEdge[u][v] = maxEdge[v][u] = cost;
for(int j = 0; j < n; j++) {
if(visited[j]) {
maxEdge[j][v] = maxEdge[v][j] = max(maxEdge[j][u], cost);
}
}
dfs(v, n);
}
}
int main() {
int testcase;
scanf("%d", &testcase);
while(testcase--) {
int n, e;
int X[1005], Y[1005], P[1005];
scanf("%d", &n);
for(int i = 0; i < n; i++)
scanf("%d %d %d", &X[i], &Y[i], &P[i]);
e = 0;
for(int i = 0; i < n; i++) {
for(int j = i + 1; j < n; j++) {
D[e++] = E(i, j, (X[i] - X[j])*(X[i] - X[j])
+ (Y[i] - Y[j])*(Y[i] - Y[j]));
}
}
double mstcost = kruscal(n, e);
double ret = 0;
for(int i = 0; i < n; i++)
visited[i] = 0;
dfs(0, n);
for(int i = 0; i < n; i++) {
for(int j = i + 1; j < n; j++) {
ret = max(ret, (P[i] + P[j])/(mstcost - maxEdge[i][j]));
}
}
printf("%.2lf\n", ret);
}
return 0;
}
Read More +

UVa 1417 - Traffic Jam

Problem

The kingdom of Tripbansai has an unusual traffic system. The city locations in the kingdom can be described as a grid and all the roads connect neighboring cities. This rectangular grid has 2 rows and C columns where every point represents a city. So there are 2 C cities and 3 C - 2 roads in this system.

Sometimes two adjacent cities become disconnected because of traffic jam, and sometimes the traffic problem has been solved so that a road can be usedd again. We can assume that every road is closed at first.

Ministry of Communications will give some instructions to you. Your task is to implement a program as a traffic response information system.

Each instruction appears as a single line in one ofthe formats below:

Close r1 c1 r2 c2 Close the road connecting the adjacent cities located on (r1, c1) and (r2, c2) .
Open r1 c1 r2 c2 Open the road connecting the adjacent cities located on (r1, c1) and (r2, c2) .
Ask r1 c1 r2 c2 Reply with Y if there exists a way from the city on (r1, c1) to the city on (r2, c2) ;
reply with N if there doesn’t.
Exit No more requests are forthcoming. The problem should exit.

Input

The first line ofthe input contains a single integer T (1$\le$T$\le$11) , representing the number of test cases that follow.

The first line of each test case consists of a single integer C (1$\le$C$\le$100000) , which is the number of columns.

There are some lines following, each for an instruction. Each test case ends with an instruction ``Exit”. There are no more than 100000 instructions in each test case. All the roads are closed initially, and each case is an independent problem.

Output

For each instruction Ask r1 c1 r2 c2, display a line containing Y or N.

Sample Input

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
3
2
Open 1 1 1 2
Open 1 2 2 2
Ask 1 1 2 2
Ask 2 1 2 2
Exit
3
Open 1 1 1 2
Ask 1 1 1 2
Close 1 1 1 2
Ask 1 1 1 2
Exit
2
Open 1 1 1 2
Open 1 2 2 2
Open 2 1 2 2
Ask 1 1 2 1
Exit

Sample Output

1
2
3
4
5
Y
N
Y
N
Y

Solution

題目描述:

對於一個 2 x C 的方格點來說,將會有 3 * C - 2 條邊。

題目解法:

維護一個區間角落四個點之間的連接資訊,也就是總共六種。

  • c[0] 左上右上
  • c[1] 左上右下
  • c[2] 左下右上
  • c[3] 左下右下
  • c[4] 左上左下
  • c[5] 右上右下

上方 r = 1 下方 r = 2 左方 c = left 右方 c = right

對於區間 [l, r] 我們只維護這個區間的資訊,不考慮繞此外的結果。
而對於區間的編號,由左而右,構成 0, 1, 2, 3, …, 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
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
struct Node {
int c[6];
}; // - \ / _ | |
Node ST[262144 + 10];
void build(int k, int l, int r) {
if(l > r) return;
if(l == r) {
memset(&ST[k], 0, sizeof(ST[k]));
return;
}
int mid = (l + r)/2;
build(k<<1, l, mid);
build(k<<1|1, mid+1, r);
}
Node combine(Node s1, Node s2) {
Node s;
s.c[0] = (s1.c[0] && s2.c[0]) || (s1.c[1] && s2.c[2]);
s.c[1] = (s1.c[0] && s2.c[1]) || (s1.c[1] && s2.c[3]);
s.c[2] = (s1.c[2] && s2.c[0]) || (s1.c[3] && s2.c[2]);
s.c[3] = (s1.c[2] && s2.c[1]) || (s1.c[3] && s2.c[3]);
s.c[4] = (s1.c[4]) || (s1.c[0] && s2.c[4] && s1.c[3]);
s.c[5] = (s2.c[5]) || (s2.c[0] && s1.c[5] && s2.c[3]);
return s;
}
void modify(int k, int l, int r, int qidx, int qfield, int qval) {
if(l > r) return;
if(l == r) {
ST[k].c[qfield] = qval;
ST[k].c[1] = (ST[k].c[0] && ST[k].c[5]) || (ST[k].c[3] && ST[k].c[4]);
ST[k].c[2] = (ST[k].c[0] && ST[k].c[4]) || (ST[k].c[3] && ST[k].c[5]);
return;
}
int mid = (l + r)/2;
if(qidx > mid)
modify(k<<1|1, mid+1, r, qidx, qfield, qval);
else
modify(k<<1, l, mid, qidx, qfield, qval);
ST[k] = combine(ST[k<<1], ST[k<<1|1]);
}
Node query(int k, int l, int r, int ql, int qr) {
if(ql <= l && r <= qr)
return ST[k];
int mid = (l + r)/2;
if(ql > mid)
return query(k<<1|1, mid+1, r, ql, qr);
else if(qr <= mid)
return query(k<<1, l, mid, ql, qr);
else
return combine(query(k<<1, l, mid, ql, qr),
query(k<<1|1, mid+1, r, ql, qr));
}
int main() {
int testcase, C;
int r1, r2, c1, c2;
int lines = 0;
char cmd[10];
scanf("%d", &testcase);
while(testcase--) {
scanf("%d", &C);
memset(ST, 0, sizeof(ST));
build(1, 0, C);
while(scanf("%s", cmd) == 1 && cmd[0] != 'E') {
scanf("%d %d %d %d", &r1, &c1, &r2, &c2);
if(cmd[0] == 'O' || cmd[0] == 'C') { // open
int qval = cmd[0] == 'O' ? 1 : 0;
if(c1 != c2) {
modify(1, 0, C, min(c1, c2), r1 == 1 ? 0 : 3, qval);
} else {
modify(1, 0, C, min(c1, c2) - 1, 5, qval);
modify(1, 0, C, min(c1, c2), 4, qval);
}
} else {
if(c1 > c2) {
swap(c1, c2);
swap(r1, r2);
}
if(r1 == r2 && c1 == c2) {
puts("Y");
} else if(r1 != r2 && c1 == c2) {
Node l = query(1, 0, C, 0, c1 - 1);
Node r = query(1, 0, C, c1, C);
if(l.c[5] || r.c[4])
puts("Y");
else
puts("N");
} else {
Node l = query(1, 0, C, 0, c1 - 1);
Node r = query(1, 0, C, c2, C);
Node m = query(1, 0, C, c1, c2 - 1);
int kc[2][2] = { {0, 1}, {2, 3} };
if(m.c[kc[r1 - 1][r2 - 1]] ||
(l.c[5] && m.c[kc[(3 - r1) - 1][r2 - 1]]) ||
(r.c[4] && m.c[kc[r1 - 1][(3 - r2) - 1]]) ||
(l.c[5] && r.c[4] && m.c[kc[(3 - r1) - 1][(3 - r2) - 1]]))
puts("Y");
else
puts("N");
}
}
}
}
return 0;
}
Read More +

UVa 1608 - Non-boring sequences

Problem

We were afraid of making this problem statement too boring, so we decided to keep it short. A sequence is called non-boring if its every connected subsequence contains a unique element, i.e. an element such that no other element of that subsequence has the same value.
Given a sequence of integers, decide whether it is non-boring.

Input

The first line of the input contains the number of test cases T. The descriptions of the test cases follow:
Each test case starts with an integer n (1 <= n <= 200000) denoting the length of the sequence. In the next line the n elements of the sequence follow, separated with single spaces. The elements are non-negative integers less than 10^9.

Output

Print the answers to the test cases in the order in which they appear in the input. For each test case print a single line containing the word non-boring or boring.

Sample Input

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

Sample Output

1
2
3
4
non-boring
boring
non-boring
boring

Solution

題目描述:

對於所有連續區間,都符合至少有一個獨特的數字。即每個區間中都會有一個數字不重複。

題目解法:

對於一個區間 [l, r] 來說,符合條件時,會存在一個獨特的數字位於 m,則對於 i in [l, m-1] and j in [m+1, r],所有 [i, j] 產生的區間必然會符合,則遞歸下去查找 [l, m-1][m+1, r] 有沒有符合。

這題有趣的地方在於-如何快速得到這個獨特數字,不過也不難想地,建出數字的前一個相同和下一個相同。判斷該數字在區間是獨特時,則前一個和下一個皆不會在區間中。

這樣仍不會通過測資,如果是想要接近中間的方式去切割,則會接受 TLE 的殘酷事實,當初在想是不是遞迴太深還怎麼的,這裡留下困惑,根據快速排序的經驗,如果切割點在中間是比較好的,複雜度為 O(n log n)

lang: cpp
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
#include <stdio.h>
#include <algorithm>
#include <map>
using namespace std;
int A[262144];
int NEXT[262144], PREV[262144];
map<int, int> R;
int dfs(int l, int r) {
if(l >= r) return 1;
for(int i = 0; i <= (r-l+1)/2; i++) {
if(NEXT[l+i] > r && PREV[l+i] < l)
return dfs(l, l+i-1) && dfs(l+i+1, r);
if(NEXT[r-i] > r && PREV[r-i] < l)
return dfs(l, r-i-1) && dfs(r-i+1, r);
}
return 0;
}
int main() {
int testcase, n;
scanf("%d", &testcase);
while(testcase--) {
scanf("%d", &n);
for(int i = 1; i <= n; i++) {
scanf("%d", &A[i]);
NEXT[i] = n+1;
PREV[i] = 0;
}
R.clear();
for(int i = 1; i <= n; i++) {
PREV[i] = R[A[i]], NEXT[PREV[i]] = i;
R[A[i]] = i;
}
puts(dfs(1, n) ? "non-boring" : "boring");
}
return 0;
}
/*
20
6
1 2 3 1 2 3
5
1 2 3 4 5
5
1 1 1 1 1
5
1 2 3 2 1
5
1 1 2 1 1
*/
Read More +

UVa 12345 - Dynamic len(set(a[L:R]))

Problem

In python, we can use len(start(a[L:R])) to calculate the number of distinct values of elements a[L], a[L+1], …, a[R-1].

Here are some interactive examples that may help you understand how it is done. Remember that the indices of python lists start from 0.

1
2
3
4
5
6
7
8
9
10
11
12
>>> a=[1,2,1,3,2,1,4]
>>> print a[1:6]
[2, 1, 3, 2, 1]
>>> print set(a[1:6])
set([1, 2, 3])
>>> print len(set(a[1:6]))
3
>>> a[3]=2
>>> print len(set(a[1:6]))
2
>>> print len(set(a[3:5]))
1

Your task is to simulate this process.

Input

There will be only one test case. The first line contains two integers n and m (1 ≤ n,m ≤ 50,000). The next line contains the original list.

All the integers are between 1 and 1,000,000 (inclusive). The next m lines contain the statements that you need to execute.

A line formatted as “M x y” (1 ≤ y ≤ 1,000,000) means “a[x] = y”, and a line formatted as “Q x y” means “print len(set(a[x:y]))”.

It is guaranteed that the statements will not cause “index out of range” error.

Output

Print the simulated result, one line for each query.

Sample Input

1
2
3
4
5
6
7 4
1 2 1 3 2 1 4
Q 1 6
M 3 2
Q 1 6
Q 3 5

Output for Sample Input

1
2
3
3
2
1

Solution

題目描述:

  1. 支持查找區間內有多少不同數字。
  2. 支持單點值修改

題目解法:

維護每一個數字的前面相同數字的位置,如果前面沒有一樣的就是 -1

1
2
3
i 0 1 2 3 4 5 6
A[] 1 2 1 3 2 1 4
P[] -1 -1 0 -1 1 2 -1

對於詢問 [l, r],返回 P[l, r] 內小於 l 的個數。

這裡使用塊狀表維護資訊,也可以使用 線段樹 + 平衡樹。

  • 塊狀表 作法

    • 對於詢問
      對於完整的塊進行二分搜尋。如果所在是不完整的塊,則窮舉搜尋。
    • 對於修改

      • 向後搜索舊值
        將指向自己的修改成原本指向的。
      • 向前搜索新值
        將指向連到前方的相同數字。
      • 向後搜索新值
        將後面最靠近的相同數字連向自己。
    • 維護資訊

      • 堆的 prev 排序後的資訊
        用在詢問 query 區間內小於 l 的二分搜
      • 堆的 value 排序後的資訊
        維護 prev 時,查找前一個和後一個的時候使用。
    • 堆更新時,最簡單是直接排序,複雜度 O(sqrt(n) * log(sqrt(n))) 看起來是不會很多,如果不使用這種方式,則必須對 prev 和 value 數組增加映射來找到相對應的原位置,然後用插入排序的方式,達到 O(sqrt(n))。但是在 UVa 運行前者在 1.200 s 左右,基本上可以不用再優化,紀錄的資訊增加一倍 又或者 代碼要長一點。

每一個操作約在 O(sqrt(n)) 時間內完整,塊狀表不用做合併操作。

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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
#include <stdio.h>
#include <map>
#include <string.h>
#include <algorithm>
using namespace std;
int pSIZE, pCOUNT;
int Pval[256][256], Ppre[256][256], Plen[256];
int A[65536], P[65536];
void build(int n) {
int pxIdx = -1, pyIdx = pSIZE;
map<int, int> PREV;
map<int, int>::iterator it;
memset(Plen, 0, sizeof(Plen));
for(int i = 0; i < n; i++) {
if(pyIdx == pSIZE)
pxIdx++, pyIdx = 0;
Pval[pxIdx][pyIdx] = A[i];
it = PREV.find(A[i]);
if(it == PREV.end()) {
Ppre[pxIdx][pyIdx] = -1;
PREV[A[i]] = i;
} else {
Ppre[pxIdx][pyIdx] = it->second;
it->second = i;
}
P[i] = Ppre[pxIdx][pyIdx];
pyIdx++;
Plen[pxIdx] = pyIdx;
}
pCOUNT = pxIdx + 1;
for(int i = 0; i < pCOUNT; i++) {
sort(Pval[i], Pval[i] + Plen[i]);
sort(Ppre[i], Ppre[i] + Plen[i]);
}
}
int query(int L, int R) {
int B = L;
int ret = 0;
while(L%pSIZE && L <= R) {
if(P[L] < B) ret++;
L++;
}
while((R+1)%pSIZE && L <= R) {
if(P[R] < B) ret++;
R--;
}
if(L > R) return ret;
L /= pSIZE, R /= pSIZE;
while(L <= R) {
int cnt = upper_bound(Ppre[L], Ppre[L] + pSIZE, B - 1) - Ppre[L];
ret += cnt;
L++;
}
return ret;
}
void updatePrev(int x) {
for(int i = x * pSIZE, j = 0; j < Plen[x]; i++, j++)
Ppre[x][j] = P[i];
sort(Ppre[x], Ppre[x] + Plen[x]);
}
void update(int x) {
for(int i = x * pSIZE, j = 0; j < Plen[x]; i++, j++)
Pval[x][j] = A[i], Ppre[x][j] = P[i];
sort(Pval[x], Pval[x] + Plen[x]);
sort(Ppre[x], Ppre[x] + Plen[x]);
}
void getNext(int x, int val, int &NEXT, int &nx) {
int y = x/pSIZE * pSIZE + Plen[x / pSIZE] - 1;
NEXT = 0x3f3f3f3f, nx = -1;
while(x%pSIZE && x <= y) {
if(A[x] == val) {
NEXT = x, nx = x / pSIZE;
return;
}
x++;
}
int L = x / pSIZE, R = pCOUNT - 1;
if(L * pSIZE < x) return;
for(int i = L; i <= R; i++) {
int pos = binary_search(Pval[i], Pval[i] + Plen[i], val);
if(pos == true) {
NEXT = i * pSIZE;
while(A[NEXT] != val) NEXT++;
nx = i;
return;
}
}
}
void getPrev(int y, int val, int &PREV, int &px) {
int x = 0;
PREV = -1, px = -1;
while((y+1)%pSIZE && x <= y) {
if(A[y] == val) {
PREV = y, px = y / pSIZE;
return;
}
y--;
}
int L = 0, R = y / pSIZE;
if(R * pSIZE > y) return;
for(int i = R; i >= L; i--) {
int pos = binary_search(Pval[i], Pval[i] + Plen[i], val);
if(pos == true) {
PREV = i * pSIZE + Plen[i] - 1;
while(A[PREV] != val) PREV--;
px = i;
return;
}
}
}
void modify(int X, int nval) {
if(A[X] == nval) return ;
int oval = A[X];
int NEXT, PREV, nx, px;
PREV = P[X], px = -1;
if(PREV >= 0) px = PREV / pSIZE;
getNext(X + 1, oval, NEXT, nx);
if(nx != -1) {
P[NEXT] = PREV;
updatePrev(nx);
}
getNext(X + 1, nval, NEXT, nx);
if(nx != -1) {
P[NEXT] = X;
updatePrev(nx);
}
getPrev(X - 1, nval, PREV, px);
A[X] = nval, P[X] = PREV;
update(X / pSIZE);
}
int main() {
// freopen("in.txt", "r+t", stdin);
// freopen("out2.txt", "w+t", stdout);
int n, m, L, R;
char cmd[4];
while(scanf("%d %d", &n, &m) == 2) {
for(pSIZE = 1; pSIZE * pSIZE < n; pSIZE++);
for(int i = 0; i < n; i++)
scanf("%d", &A[i]);
build(n);
while(m--) {
scanf("%s %d %d", cmd, &L, &R);
if(cmd[0] == 'Q') {
R--;
int r = query(L, R);
printf("%d\n", r);
} else {
modify(L, R);
}
}
}
return 0;
}
/*
30 50
4 19 18 17 16 7 16 9 18 14 4 11 4 2 8 8 1 3 1 5 5 8 3 8 11 17 10 0 2 16
M 20 12
Q 2 29
M 8 9
Q 7 7
M 25 12
M 19 13
Q 12 22
Q 8 11
M 5 5
M 15 8
Q 9 26
*/
Read More +

程序设计实习 MOOC Week 6(待補)

前提概要

這一道題目,照理來講是一版一版慢慢加強,但是突然接收到巨噁模擬題。在很有耐心看完後,看起來是不得度使用物件導向的多形來模擬,不然程式代碼會寫得非常難看,難看也倒還好,只是怕寫不出來。

不過礙於時間關係,寫到一半還是放棄了,於是附加的代碼是 失敗 的。

卡在 RE 狀態,明明本地端測試不會有噴出 RE 資訊,上傳卻發生了 RE,暫時沒有辦法去解決。
題目來源

A - 魔兽世界终极版

題目

总时间限制: 2000ms 内存限制: 65536kB

描述

魔兽世界的西面是红魔军的司令部,东面是蓝魔军的司令部。两个司令部之间是依次排列的若干城市,城市从西向东依次编号为1,2,3 …. N ( N <= 20 )。红魔军的司令部算作编号为0的城市,蓝魔军的司令部算作编号为N+1的城市。司令部有生命元,用于制造武士。

两军的司令部都会制造武士。武士一共有 dragon 、ninja、iceman、lion、wolf 五种。每种武士都有编号、生命值、攻击力这三种属性。

双方的武士编号都是从1开始计算。红方制造出来的第 n 个武士,编号就是n。同样,蓝方制造出来的第 n 个武士,编号也是n。

武士在刚降生的时候有一个初始的生命值,生命值在战斗中会发生变化,如果生命值减少到0(生命值变为负数时应当做变为0处理),则武士死亡(消失)。

有的武士可以拥有武器。武器有三种,sword, bomb,和arrow,编号分别为0,1,2。

武士降生后就朝对方司令部走,在经过的城市如果遇到敌人(同一时刻每个城市最多只可能有1个蓝武士和一个红武士),就会发生战斗。每次战斗只有一方发起主动进攻一次。被攻击者生命值会减去进攻者的攻击力值和进攻者手中sword的攻击力值。被进攻者若没死,就会发起反击,被反击者的生命值要减去反击者攻击力值的一半(去尾取整)和反击者手中sword的攻击力值。反击可能致敌人于死地。

如果武士在战斗中杀死敌人(不论是主动进攻杀死还是反击杀死),则其司令部会立即向其发送8个生命元作为奖励,使其生命值增加8。当然前提是司令部得有8个生命元。如果司令部的生命元不足以奖励所有的武士,则优先奖励距离敌方司令部近的武士。

如果某武士在某城市的战斗中杀死了敌人,则该武士的司令部立即取得该城市中所有的生命元。注意,司令部总是先完成全部奖励工作,然后才开始从各个打了胜仗的城市回收生命元。对于因司令部生命元不足而领不到奖励的武士,司令部也不会在取得战利品生命元后为其补发奖励。

如果一次战斗的结果是双方都幸存(平局),则双方都不能拿走发生战斗的城市的生命元。

城市可以插旗子,一开始所有城市都没有旗子。在插红旗的城市,以及编号为奇数的无旗城市,由红武士主动发起进攻。在插蓝旗的城市,以及编号为偶数的无旗城市,由蓝武士主动发起进攻。

当某个城市有连续两场战斗都是同一方的武士杀死敌人(两场战斗之间如果有若干个战斗时刻并没有发生战斗,则这两场战斗仍然算是连续的;但如果中间有平局的战斗,就不算连续了) ,那么该城市就会插上胜方的旗帜,若原来插着败方的旗帜,则败方旗帜落下。旗帜一旦插上,就一直插着,直到被敌人更换。一个城市最多只能插一面旗帜,旗帜没被敌人更换前,也不会再次插同颜色的旗。

各种武器有其特点:

sword武器的初始攻击力为拥有它的武士的攻击力的20%(去尾取整)。但是sword每经过一次战斗(不论是主动攻击还是反击),就会变钝,攻击力变为本次战斗前的80% (去尾取整)。sword攻击力变为0时,视为武士失去了sword。如果武士降生时得到了一个初始攻击力为0的sword,则视为武士没有sword.

arrow有一个攻击力值R。如果下一步要走到的城市有敌人,那么拥有arrow的武士就会放箭攻击下一个城市的敌人(不能攻击对方司令部里的敌人)而不被还击。arrow使敌人的生命值减少R,若减至小于等于0,则敌人被杀死。arrow使用3次后即被耗尽,武士失去arrow。两个相邻的武士可能同时放箭把对方射死。

拥有bomb的武士,在战斗开始前如果判断自己将被杀死(不论主动攻击敌人,或者被敌人主动攻击都可能导致自己被杀死,而且假设武士可以知道敌人的攻击力和生命值),那么就会使用bomb和敌人同归于尽。武士不预测对方是否会使用bomb。

武士使用bomb和敌人同归于尽的情况下,不算是一场战斗,双方都不能拿走城市的生命元,也不影响城市的旗帜。

不同的武士有不同的特点。

dragon可以拥有一件武器。编号为n的dragon降生时即获得编号为 n%3 的武器。dragon还有“士气”这个属性,是个浮点数,其值为它降生后其司令部剩余生命元的数量除以造dragon所需的生命元数量。dragon 在一次在它主动进攻的战斗结束后,如果还没有战死,而且士气值大于0.8,就会欢呼。dragon每取得一次战斗的胜利(敌人被杀死),士气就会增加0.2,每经历一次未能获胜的战斗,士气值就会减少0.2。士气增减发生在欢呼之前。

ninjia可以拥有两件武器。编号为n的ninjia降生时即获得编号为 n%3 和 (n+1)%3的武器。ninja 挨打了也从不反击敌人。

iceman有一件武器。编号为n的iceman降生时即获得编号为 n%3 的武器。iceman 每前进两步,在第2步完成的时候,生命值会减少9,攻击力会增加20。但是若生命值减9后会小于等于0,则生命值不减9,而是变为1。即iceman不会因走多了而死。

lion 有“忠诚度”这个属性,其初始值等于它降生之后其司令部剩余生命元的数目。每经过一场未能杀死敌人的战斗,忠诚度就降低K。忠诚度降至0或0以下,则该lion逃离战场,永远消失。但是已经到达敌人司令部的lion不会逃跑。Lion在己方司令部可能逃跑。lion 若是战死,则其战斗前的生命值就会转移到对手身上。所谓“战斗前”,就是每个小时的40分前的一瞬间。

wolf降生时没有武器,但是在战斗中如果获胜(杀死敌人),就会缴获敌人的武器,但自己已有的武器就不缴获了。被缴获的武器当然不能算新的,已经被用到什么样了,就是什么样的。

以下是不同时间会发生的不同事件:

在每个整点,即每个小时的第0分, 双方的司令部中各有一个武士降生。

红方司令部按照 iceman、lion、wolf、ninja、dragon 的顺序制造武士。

蓝方司令部按照 lion、dragon、ninja、iceman、wolf 的顺序制造武士。

制造武士需要生命元。

制造一个初始生命值为 m 的武士,司令部中的生命元就要减少 m 个。

如果司令部中的生命元不足以制造某武士,那么司令部就等待,直到获得足够生命元后的第一个整点,才制造该武士。例如,在2:00,红方司令部本该制造一个 wolf ,如果此时生命元不足,那么就会等待,直到生命元足够后的下一个整点,才制造一个 wolf。

在每个小时的第5分,该逃跑的lion就在这一时刻逃跑了。

在每个小时的第10分:所有的武士朝敌人司令部方向前进一步。即从己方司令部走到相邻城市,或从一个城市走到下一个城市。或从和敌军司令部相邻的城市到达敌军司令部。

在每个小时的第20分:每个城市产出10个生命元。生命元留在城市,直到被武士取走。

在每个小时的第30分:如果某个城市中只有一个武士,那么该武士取走该城市中的所有生命元,并立即将这些生命元传送到其所属的司令部。

在每个小时的第35分,拥有arrow的武士放箭,对敌人造成伤害。放箭事件应算发生在箭发出的城市。注意,放箭不算是战斗,因此放箭的武士不会得到任何好处。武士在没有敌人的城市被箭射死也不影响其所在城市的旗帜更换情况。

在每个小时的第38分,拥有bomb的武士评估是否应该使用bomb。如果是,就用bomb和敌人同归于尽。

在每个小时的第40分:在有两个武士的城市,会发生战斗。 如果敌人在5分钟前已经被飞来的arrow射死,那么仍然视为发生了一场战斗,而且存活者视为获得了战斗的胜利。此情况下不会有“武士主动攻击”,“武士反击”,“武士战死”的事件发生,但战斗胜利后应该发生的事情都会发生。如Wolf一样能缴获武器,旗帜也可能更换,等等。在此情况下,Dragon同样会通过判断是否应该轮到自己主动攻击来决定是否欢呼。

在每个小时的第50分,司令部报告它拥有的生命元数量。

在每个小时的第55分,每个武士报告其拥有的武器情况。

武士到达对方司令部后就算完成任务了,从此就呆在那里无所事事。

任何一方的司令部里若是出现了2个敌人,则认为该司令部已被敌人占领。

任何一方的司令部被敌人占领,则战争结束。战争结束之后就不会发生任何事情了。

给定一个时间,要求你将从0点0分开始到此时间为止的所有事件按顺序输出。事件及其对应的输出样例如下:

1) 武士降生

输出样例: 000:00 blue lion 1 born

表示在 0点0分,编号为1的蓝魔lion武士降生
如果造出的是dragon,那么还要多输出一行,例:

000:00 blue dragon 1 born
Its morale is 23.34

表示该该dragon降生时士气是23. 34(四舍五入到小数点后两位)

如果造出的是lion,那么还要多输出一行,例:
000:00 blue lion 1 born
Its loyalty is 24

表示该lion降生时的忠诚度是24

2) lion逃跑

输出样例: 000:05 blue lion 1 ran away
表示在 0点5分,编号为1的蓝魔lion武士逃走

3) 武士前进到某一城市

输出样例: 000:10 red iceman 1 marched to city 1 with 20 elements and force 30
表示在 0点10分,红魔1号武士iceman前进到1号城市,此时他生命值为20,攻击力为30
对于iceman,输出的生命值和攻击力应该是变化后的数值

4)武士放箭

输出样例: 000:35 blue dragon 1 shot
表示在 0点35分,编号为1的蓝魔dragon武士射出一支箭。如果射出的箭杀死了敌人,则应如下输出:
000:35 blue dragon 1 shot and killed red lion 4
表示在 0点35分,编号为1的蓝魔dragon武士射出一支箭,杀死了编号为4的红魔lion。

5)武士使用bomb

输出样例: 000:38 blue dragon 1 used a bomb and killed red lion 7
表示在 0点38分,编号为1的蓝魔dragon武士用炸弹和编号为7的红魔lion同归于尽。

6) 武士主动进攻

输出样例:000:40 red iceman 1 attacked blue lion 1 in city 1 with 20 elements and force 30
表示在0点40分,1号城市中,红魔1号武士iceman 进攻蓝魔1号武士lion,在发起进攻前,红魔1号武士iceman生命值为20,攻击力为 30

7) 武士反击

输出样例:001:40 blue dragon 2 fought back against red lion 2 in city 1
表示在1点40分,1号城市中,蓝魔2号武士dragon反击红魔2号武士lion

8) 武士战死

输出样例:001:40 red lion 2 was killed in city 1
被箭射死的武士就不会有这一条输出。

9) 武士欢呼

输出样例:003:40 blue dragon 2 yelled in city 4

10) 武士获取生命元( elements )

输出样例:001:40 blue dragon 2 earned 10 elements for his headquarter

11) 旗帜升起

输出样例:004:40 blue flag raised in city 4

12) 武士抵达敌军司令部

输出样例:001:10 red iceman 1 reached blue headquarter with 20 elements and force 30
(此时他生命值为20,攻击力为30)对于iceman,输出的生命值和攻击力应该是变化后的数值

13) 司令部被占领

输出样例:003:10 blue headquarter was taken

14)司令部报告生命元数量

000:50 100 elements in red headquarter
000:50 120 elements in blue headquarter
表示在0点50分,红方司令部有100个生命元,蓝方有120个

15)武士报告武器情况

000:55 blue wolf 2 has arrow(2),bomb,sword(23)
000:55 blue wolf 4 has no weapon
000:55 blue wolf 5 has sword(20)
表示在0点55分,蓝魔2号武士wolf有一支arrow(这支arrow还可以用2次),一个bomb,还有一支攻击力为23的sword。
蓝魔4号武士wolf没武器。
蓝魔5号武士wolf有一支攻击力为20的sword。
交代武器情况时,次序依次是:arrow,bomb,sword。如果没有某种武器,某种武器就不用提。报告时,先按从西向东的顺序所有的红武士报告,然后再从西向东所有的蓝武士报告。

输出事件时:

首先按时间顺序输出;

同一时间发生的事件,按发生地点从西向东依次输出. 武士前进的事件, 算是发生在目的地。

在一次战斗中有可能发生上面的 6 至 11 号事件。这些事件都算同时发生,其时间就是战斗开始时间。一次战斗中的这些事件,序号小的应该先输出。

两个武士同时抵达同一城市,则先输出红武士的前进事件,后输出蓝武士的。

显然,13号事件发生之前的一瞬间一定发生了12号事件。输出时,这两件事算同一时间发生,但是应先输出12号事件

虽然任何一方的司令部被占领之后,就不会有任何事情发生了。但和司令部被占领同时发生的事件,全都要输出。

输入

第一行是t,代表测试数据组数
每组样例共三行。
第一行,五个整数 M,N,R,K, T。其含义为:

每个司令部一开始都有M个生命元( 1 <= M <= 10000)
两个司令部之间一共有N个城市( 1 <= N <= 20 )
arrow的攻击力是R
lion每经过一场未能杀死敌人的战斗,忠诚度就降低K。
要求输出从0时0分开始,到时间T为止(包括T) 的所有事件。T以分钟为单位,0 <= T <= 5000

第二行:五个整数,依次是 dragon 、ninja、iceman、lion、wolf 的初始生命值。它们都大于0小于等于10000

第三行:五个整数,依次是 dragon 、ninja、iceman、lion、wolf 的攻击力。它们都大于0小于等于10000

输出

对每组数据,先输出一行:
Case n:
如对第一组数据就输出 Case1:
然后按恰当的顺序和格式输出到时间T为止发生的所有事件。每个事件都以事件发生的时间开头,时间格式是“时: 分”,“时”有三位,“分”有两位。

样例输入

1
20 1 10 10 1000
20 20 30 10 20
5 5 5 5 5

样例输出

Case 1:
000:00 blue lion 1 born
Its loyalty is 10
000:10 blue lion 1 marched to city 1 with 10 elements and force 5
000:30 blue lion 1 earned 10 elements for his headquarter
000:50 20 elements in red headquarter
000:50 20 elements in blue headquarter
000:55 blue lion 1 has no weapon
001:00 blue dragon 2 born
Its morale is 0.00
001:10 blue lion 1 reached red headquarter with 10 elements and force 5
001:10 blue dragon 2 marched to city 1 with 20 elements and force 5
001:30 blue dragon 2 earned 10 elements for his headquarter
001:50 20 elements in red headquarter
001:50 10 elements in blue headquarter
001:55 blue lion 1 has no weapon
001:55 blue dragon 2 has arrow(3)
002:10 blue dragon 2 reached red headquarter with 20 elements and force 5
002:10 red headquarter was taken

失敗代碼

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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
#include <stdio.h>
#include <algorithm>
#include <map>
#include <iostream>
#include <vector>
#include <string.h>
using namespace std;
class Info {
public:
static int M, N, R, K, T;
static map<string, int> HP, ATK;
static string Mkind[];
static string Rkind[];
static string Bkind[];
};
int Info::M = 0, Info::N = 0, Info::R = 0, Info::K = 0, Info::T = 0;
map<string, int> Info::HP, Info::ATK;
string Info::Mkind[] = {"dragon", "ninja", "iceman", "lion", "wolf"};
string Info::Rkind[] = {"dragon", "iceman", "lion", "wolf", "ninja"};
string Info::Bkind[] = {"wolf", "lion", "dragon", "ninja", "iceman"};
class Weapon {
public:
virtual void show() {};
virtual int getMeleeAttack() {
return 0;
};
virtual int actMeleeAttack() {
return 0;
};
virtual int getRangeAttack() {
return 0;
}
virtual int actRangeAttack() {
return 0;
}
virtual int getBombAttack() {
return 0;
}
virtual int actBombAttack() {
return 0;
}
};
class Sword: public Weapon {
public:
int attack;
Sword(int _attack): attack(_attack) {
}
int getMeleeAttack() {
return attack;
}
int actMeleeAttack() {
attack = attack * 8 / 10;
return attack > 0;
}
void show() {
printf("sword(%d)", attack);
}
};
class Arrow: public Weapon {
public:
int R, usedTime;
Arrow(int _R): R(_R) {
usedTime = 0;
}
int getRangeAttack() {
return usedTime < 3 ? R : 0;
}
int actRangeAttack() {
usedTime++;
return usedTime >= 3;
}
void show() {
printf("arrow(%d)", 3 - usedTime);
}
};
class Bomb: public Weapon {
public:
Bomb() {
}
int getBombAttack() {
return 1;
}
void show() {
printf("bomb");
}
};
class WeaponFactory {
public:
static Weapon* build(int n, int attack) {
if(n == 0) {
if(attack / 5 <= 0)
return NULL;
return new Sword(attack/5);
}
else if(n == 2)
return new Arrow(Info::R);
else
return new Bomb();
}
};
class Warrior {
public:
int n;
int life;
Warrior(int _n, int _life): n(_n), life(_life) {
}
virtual void show() {};
virtual void showName() {};
virtual void showWeapon() {};
virtual int getAttack() {return 0;}
virtual int getFled() {return 0;}
virtual int getMeleeAttack() {return 0;}
virtual void actMeleeAttack() {}
virtual int getBackAttack() {return 0;}
virtual void actBackAttack() {}
virtual void move() {};
virtual void actRangeAttack(Warrior* o) {};
};
class Dragon: public Warrior {
public:
Weapon *weapon;
float morale;
Dragon(int _n, int _life, float _morale): Warrior(_n, _life), morale(_morale) {
weapon = WeaponFactory::build(n%3, Info::ATK["dragon"]);
}
void show() {
printf("dragon %d born\n", n);
printf("Its morale is %.2f\n", morale);
}
void showName() {
printf("dragon %d", n);
}
void showWeapon() {
if(weapon != NULL)
weapon->show();
else
printf("no weapon");
}
int getAttack() {
return Info::ATK["dragon"];
}
int getMeleeAttack() {
int m = 0;
if(weapon != NULL)
m = weapon->getMeleeAttack();
return getAttack() + m;
}
int getBackAttack() {
int m = 0;
if(weapon != NULL)
m = weapon->getMeleeAttack();
return getAttack()/2 + m;
}
void actMeleeAttack() {
if(weapon != NULL) {
int f = weapon->actMeleeAttack();
if(f == 0) {
delete weapon;
weapon = NULL;
}
}
}
void actBackAttack() {
actMeleeAttack();
}
void actRangeAttack(Warrior* o) {
if(weapon != NULL) {
o->life -= weapon->getRangeAttack();
int f = weapon->actRangeAttack();
if(f == 1) {
delete weapon;
weapon = NULL;
}
}
}
};
class Ninja: public Warrior {
public:
Weapon *weapon[2];
Ninja(int _n, int _life): Warrior(_n, _life) {
weapon[0] = WeaponFactory::build(n%3, Info::ATK["ninja"]);
weapon[1] = WeaponFactory::build((n+1)%3, Info::ATK["ninja"]);
}
void show() {
printf("ninja %d born\n", n);
}
void showName() {
printf("ninja %d", n);
}
void showWeapon() {
int f1 = n%3, f2 = (n+1)%3, f = 0;
if(f1 < f2) {
if(weapon[0] != NULL)
weapon[0]->show(), f++;
if(f) putchar(',');
if(weapon[1] != NULL)
weapon[1]->show(), f++;
} else {
if(weapon[1] != NULL)
weapon[1]->show(), f++;
if(f) putchar(',');
if(weapon[0] != NULL)
weapon[0]->show(), f++;
}
if(f == 0)
printf("no weapon");
}
int getAttack() {
return Info::ATK["ninja"];
}
int getMeleeAttack() {
int m = 0;
if(weapon[0] != NULL)
m += weapon[0]->getMeleeAttack();
if(weapon[1] != NULL)
m += weapon[1]->getMeleeAttack();
return getAttack() + m;
}
int getBackAttack() {
int m = 0;
if(weapon[0] != NULL)
m += weapon[0]->getMeleeAttack();
if(weapon[1] != NULL)
m += weapon[1]->getMeleeAttack();
return getAttack()/2 + m;
}
void actMeleeAttack() {
if(weapon[0] != NULL) {
int f = weapon[0]->actMeleeAttack();
if(f == 0) {
delete weapon[0];
weapon[0] = NULL;
}
}
if(weapon[1] != NULL) {
int f = weapon[1]->actMeleeAttack();
if(f == 0) {
delete weapon[1];
weapon[1] = NULL;
}
}
}
void actBackAttack() {
actMeleeAttack();
}
void actRangeAttack(Warrior* o) {
for(int i = 0; i < 2; i++) {
if(weapon[i] != NULL) {
o->life -= weapon[i]->getRangeAttack();
int f = weapon[i]->actRangeAttack();
if(f == 1)
weapon[i] = NULL;
}
}
}
};
class Iceman: public Warrior {
public:
Weapon *weapon;
int move_count;
int attack;
Iceman(int _n, int _life): Warrior(_n, _life) {
weapon = WeaponFactory::build(n%3, Info::ATK["iceman"]);
move_count = 0;
attack = Info::ATK["iceman"];
}
void show(){
printf("iceman %d born\n", n);
}
void showName() {
printf("iceman %d", n);
}
void showWeapon() {
if(weapon != NULL)
weapon->show();
else
printf("no weapon");
}
int getAttack() {
return attack;
}
int getMeleeAttack() {
int m = 0;
if(weapon != NULL)
m = weapon->getMeleeAttack();
return getAttack() + m;
}
int getBackAttack() {
int m = 0;
if(weapon != NULL)
m = weapon->getMeleeAttack();
return getAttack()/2 + m;
}
void actMeleeAttack() {
if(weapon != NULL) {
int f = weapon->actMeleeAttack();
if(f == 0) {
delete weapon;
weapon = NULL;
}
}
}
void actBackAttack() {
actMeleeAttack();
}
void actRangeAttack(Warrior* o) {
if(weapon != NULL) {
o->life -= weapon->getRangeAttack();
int f = weapon->actRangeAttack();
if(f == 1) {
delete weapon;
weapon = NULL;
}
}
}
void move() {
move_count++;
if(move_count == 2) {
attack += 20;
life -= 9;
if(life <= 0)
life = 1;
move_count = 0;
}
}
};
class Lion: public Warrior {
public:
int loyalty;
Lion(int _n, int _life, int _loyalty): Warrior(_n, _life), loyalty(_loyalty) {
}
void show() {
printf("lion %d born\n", n);
printf("Its loyalty is %d\n", loyalty);
}
void showName() {
printf("lion %d", n);
}
void showWeapon() {
printf("no weapon");
}
int getAttack() {
return Info::ATK["lion"];
}
int getMeleeAttack() {
return getAttack();
}
int getBackAttack() {
return getAttack()/2;
}
int getFled() {
return loyalty <= 0;
}
};
class Wolf: public Warrior {
public:
Weapon *weapon[3];
Wolf(int _n, int _life): Warrior(_n, _life) {
weapon[0] = weapon[1] = weapon[2] = NULL;
}
void show() {
printf("wolf %d born\n", n);
}
void showName() {
printf("wolf %d", n);
}
void showWeapon() {
int f = 0;
for(int i = 0; i < 3; i++) {
if(weapon[i] != NULL) {
if(f) putchar(',');
weapon[i]->show(), f++;
}
}
if(f == 0)
printf("no weapon");
}
int getAttack() {
return Info::ATK["wolf"];
}
int getMeleeAttack() {
int m = 0;
if(weapon[2] != NULL)
m = weapon[2]->getMeleeAttack();
return getAttack() + m;
}
int getBackAttack() {
int m = 0;
if(weapon[2] != NULL)
m = weapon[2]->getMeleeAttack();
return getAttack()/2 + m;
}
void actMeleeAttack() {
if(weapon[2] != NULL) {
int f = weapon[2]->actMeleeAttack();
if(f == 0) {
delete weapon[2];
weapon[2] = NULL;
}
}
}
void actBackAttack() {
actMeleeAttack();
}
void actRangeAttack(Warrior* o) {
if(weapon[2] != NULL) {
o->life -= weapon[2]->getRangeAttack();
int f = weapon[2]->actRangeAttack();
if(f == 1)
weapon[2] = NULL;
}
}
};
class WarriorFactory {
public:
static Warrior* build(string kind, int n, float _morale, int _loyalty) {
if(!strcmp(kind.c_str(), "dragon"))
return new Dragon(n, Info::HP[kind], _morale);
else if(!strcmp(kind.c_str(), "ninja"))
return new Ninja(n, Info::HP[kind]);
else if(!strcmp(kind.c_str(), "iceman"))
return new Iceman(n, Info::HP[kind]);
else if(!strcmp(kind.c_str(), "lion"))
return new Lion(n, Info::HP[kind], _loyalty);
else
return new Wolf(n, Info::HP[kind]);
}
};
class Headquarter {
public:
int HP;
int dir;
int n;
Headquarter(int _HP, int _dir): HP(_HP), dir(_dir) {
n = 1;
}
void produce(vector<Warrior*> R[], vector<Warrior*> B[], int hh, int mm) {
string kind;
int born_cost;
if(dir == 1) { // RED
kind = Info::Rkind[n % 5];
} else { // BLUE
kind = Info::Bkind[n % 5];
}
born_cost = Info::HP[kind];
if(born_cost > HP)
return;
HP -= born_cost;
printf("%03d:%02d %s ", hh, mm, dir == 1 ? "red" : "blue");
Warrior *w = WarriorFactory::build(kind, n, (double) HP/ Info::HP[kind], HP);
w->show();
if(dir == 1) { // RED
R[0].push_back(w);
} else {
B[Info::N + 1].push_back(w);
}
n++;
}
};
void simulate() {
Headquarter RED(Info::M, 1), BLUE(Info::M, -1);
int timescale[] = {0, 5, 10, 20, 30, 35, 38, 40, 50, 55};
vector<Warrior*> R[Info::N + 2], B[Info::N + 2];
int cityHP[Info::N+2], cityFlag[Info::N+2], cityBattle[Info::N+2];
// cityFlag[], cityBattle[], NONE: 0, RED: 1, BLUE: 2
for(int i = 0; i <= Info::N + 1; i++)
cityHP[i] = cityFlag[i] = cityBattle[i] = 0;
for(int hour = 0; ; hour++) {
for(int i = 0; i < 10; i++) {
if(hour * 60 + timescale[i] > Info::T)
return;
int t = timescale[i];
if(t == 0) { // fixed
RED.produce(R, B, hour, t);
BLUE.produce(R, B, hour, t);
} else if(t == 5) { // fixed
for(int i = 0; i <= Info::N; i++) {
if(R[i].size() > 0) {
if(R[i][0]->getFled()) {
printf("%03d:%02d red ", hour, t);
R[i][0]->showName();
printf(" ran away\n");
R[i].clear();
}
}
}
for(int i = 1; i <= Info::N+1; i++) {
if(B[i].size() > 0) {
if(B[i][0]->getFled()) {
printf("%03d:%02d blue ", hour, t);
B[i][0]->showName();
printf(" ran away\n");
B[i].clear();
}
}
}
} else if(t == 10) { // fixed
for(int i = 0; i <= Info::N + 1; i++) {
if(R[i].size() > 0 && i <= Info::N) {
printf("%03d:%02d red ", hour, t);
R[i][0]->showName();
R[i][0]->move();
if(i + 1 < Info::N + 1)
printf(" marched to city %d with %d elements and force %d\n", i + 1, R[i][0]->life, R[i][0]->getAttack());
else
printf(" reached blue headquarter with %d elements and force %d\n", R[i][0]->life, R[i][0]->getAttack());
}
if(B[i].size() > 0 && i > 0) {
printf("%03d:%02d blue ", hour, t);
B[i][0]->showName();
B[i][0]->move();
if(i - 1 > 0)
printf(" marched to city %d with %d elements and force %d\n", i - 1, B[i][0]->life, B[i][0]->getAttack());
else
printf(" reached red headquarter with %d elements and force %d\n", B[i][0]->life, B[i][0]->getAttack());
}
}
for(int i = Info::N; i >= 0; i--) {
if(R[i].size() > 0) {
R[i+1].push_back(R[i][0]);
R[i].clear();
}
}
for(int i = 1; i <= Info::N + 1; i++) {
if(B[i].size() > 0) {
B[i-1].push_back(B[i][0]);
B[i].clear();
}
}
if(B[0].size() >= 2) {
printf("%03d:%02d red headquarter was taken\n", hour, t);
return ;
}
if(R[Info::N+1].size() >= 2) {
printf("%03d:%02d blue headquarter was taken\n", hour, t);
return ;
}
} else if(t == 20) { // fixed
for(int i = 1; i <= Info::N; i++)
cityHP[i] += 10;
} else if(t == 30) { // fixed
for(int i = 1; i <= Info::N; i++) {
if(R[i].size() == 1 && B[i].size() == 0) {
printf("%03d:%02d red ", hour, t);
R[i][0]->showName();
printf(" earned %d elements for his headquarter\n", cityHP[i]);
RED.HP += cityHP[i], cityHP[i] = 0;
}
if(R[i].size() == 0 && B[i].size() == 1) {
printf("%03d:%02d blue ", hour, t);
B[i][0]->showName();
printf(" earned %d elements for his headquarter\n", cityHP[i]);
BLUE.HP += cityHP[i], cityHP[i] = 0;
}
}
} else if(t == 35) { // fixed
for(int i = 0; i <= Info::N; i++) {
if(R[i].size() > 0 && B[i+1].size() > 0) {
R[i][0]->actRangeAttack(B[i+1][0]);
}
}
for(int i = 1; i <= Info::N + 1; i++) {
if(B[i].size() > 0 && R[i-1].size() > 0) {
B[i][0]->actRangeAttack(R[i-1][0]);
}
}
} else if(t == 38) { // fixed
for(int i = 0; i <= Info::N + 1; i++) {
if(R[i].size() > 0 && B[i].size() > 0) {
int rATK = R[i][0]->getMeleeAttack();
int bATK = B[i][0]->getMeleeAttack();
if(bATK >= R[i][0]->life) {
printf("%03d:%02d red ", hour, t);
R[i][0]->showName();
printf(" used a bomb and killed blue ");;
B[i][0]->showName();
puts("");
}
if(rATK >= B[i][0]->life) {
printf("%03d:%02d blue ", hour, t);
B[i][0]->showName();
printf(" used a bomb and killed red ");;
R[i][0]->showName();
puts("");
}
if(bATK >= R[i][0]->life || rATK >= B[i][0]->life) {
delete R[i][0];
R[i].clear();
delete B[i][0];
B[i].clear();
}
}
}
} else if(t == 40) {
int RB[Info::N+2];
for(int i = 1; i <= Info::N; i++) {
RB[i] = 0;
}
for(int i = 1; i <= Info::N; i++) {
if(R[i].size() > 0 && B[i].size() > 0) {
if(R[i][0]->life <= 0 || B[i][0]->life <= 0) {
} else {
if(cityFlag[i] == 1 || (cityFlag[i] == 0 && i%2 == 1)) {
int AT = R[i][0]->getMeleeAttack();
B[i][0]->life -= AT;
if(B[i][0]->life > 0) {
int BAT = B[i][0]->getBackAttack();
R[i][0]->life -= AT;
}
} else {
int AT = B[i][0]->getMeleeAttack();
R[i][0]->life -= AT;
if(R[i][0]->life > 0) {
int BAT = R[i][0]->getBackAttack();
B[i][0]->life -= AT;
}
}
}
if(R[i][0]->life > 0 && B[i][0]->life <= 0) {
RB[i] = 1;
if(cityBattle[i] == 1) {
cityFlag[i] = 1;
} else if(cityBattle[i] == 0) {
cityBattle[i] = 1;
}
}
if(B[i][0]->life > 0 && R[i][0]->life <= 0) {
RB[i] = 2;
if(cityBattle[i] == 2) {
cityFlag[i] = 2;
} else if(cityBattle[i] == 0) {
cityBattle[i] = 2;
}
}
}
if(R[i].size() > 0 && R[i][0]->life <= 0) {
delete R[i][0];
R[i].clear();
}
if(B[i].size() > 0 && B[i][0]->life <= 0) {
delete B[i][0];
B[i].clear();
}
}
for(int i = Info::N + 1; i >= 0; i--) {
if(RED.HP >= 8 && RB[i] == 1) {
RED.HP -= 8;
R[i][0]->life += 8;
}
}
for(int i = 0; i <= Info::N + 1; i++) {
if(BLUE.HP >= 8 && RB[i] == 2) {
BLUE.HP -= 8;
B[i][0]->life += 8;
}
}
for(int i = 0; i <= Info::N + 1; i++) {
if(RB[i] == 1) {
RED.HP += cityHP[i];
cityHP[i] = 0;
}
if(RB[i] == 2) {
BLUE.HP += cityHP[i];
cityHP[i] = 0;
}
}
} else if(t == 50) { // fixed
printf("%03d:%02d %d elements in red headquarter\n", hour, t, RED.HP);
printf("%03d:%02d %d elements in blue headquarter\n", hour, t, BLUE.HP);
} else if(t == 55) { // fixed
for(int i = 0; i <= Info::N + 1; i++) {
if(R[i].size() == 1) {
printf("%03d:%02d red ", hour, t);
R[i][0]->showName();
printf(" has ");
R[i][0]->showWeapon();
puts("");
}
if(B[i].size() == 1) {
printf("%03d:%02d blue ", hour, t);
B[i][0]->showName();
printf(" has ");
B[i][0]->showWeapon();
puts("");
}
}
}
}
}
}
int main() {
freopen("in.txt", "r+t", stdin);
freopen("out-my.txt", "w+t", stdout);
int testcase, cases = 0;
scanf("%d", &testcase);
while(testcase--) {
scanf("%d %d %d %d %d", &Info::M, &Info::N, &Info::R, &Info::K, &Info::T);
for(int i = 0; i < 5; i++)
scanf("%d", &Info::HP[Info::Mkind[i]]);
for(int i = 0; i < 5; i++)
scanf("%d", &Info::ATK[Info::Mkind[i]]);
printf("Case %d:\n", ++cases);
simulate();
}
return 0;
}
Read More +

程序设计实习 MOOC Week 9 DEX

接續上一篇

D - 热血格斗场

題目

总时间限制: 1000ms 内存限制: 65536kB

描述

为了迎接08年的奥运会,让大家更加了解各种格斗运动,facer新开了一家热血格斗场。格斗场实行会员制,但是新来的会员不需要交入会费,而只要同一名老会员打一场表演赛,证明自己的实力。

我们假设格斗的实力可以用一个正整数表示,成为实力值。另外,每个人都有一个唯一的id,也是一个正整数。为了使得比赛更好看,每一个新队员都会选择与他实力最为接近的人比赛,即比赛双方的实力值之差的绝对值越小越好,如果有两个人的实力值与他差别相同,则他会选择比他弱的那个(显然,虐人必被虐好)。

不幸的是,Facer一不小心把比赛记录弄丢了,但是他还保留着会员的注册记录。现在请你帮facer恢复比赛纪录,按照时间顺序依次输出每场比赛双方的id。

输入

第一行一个数n(0 < n <=100000),表示格斗场新来的会员数(不包括facer)。以后n行每一行两个数,按照入会的时间给出会员的id和实力值。一开始,facer就算是会员,id为1,实力值1000000000。输入保证两人的实力值不同。

输出

N行,每行两个数,为每场比赛双方的id,新手的id写在前面。

样例输入

3
2 1
3 3
4 2

样例输出

2 1
3 2
4 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
35
36
// http://cxsjsxmooc.openjudge.cn/
#include <stdio.h>
#include <stdlib.h>
#include <set>
using namespace std;
int main() {
#define oo 0x3f3f3f3f
for(int n, id, power; scanf("%d", &n) == 1;) {
set< pair<int, int> > S;
S.insert(make_pair(1000000000, 1));
for(int i = 0; i < n; i++) {
scanf("%d %d", &id, &power);
S.insert(make_pair(power, id));
set< pair<int, int> >::iterator it;
it = S.find(make_pair(power, id));
pair<int, int> f1, f2;
f1 = make_pair(-oo, 0);
f2 = make_pair(oo, 0);
if(it != S.begin()) {
it--;
f1 = *it;
it++;
}
if(it != S.end()) {
it++;
f2 = *it;
it--;
}
if(abs(f2.first - power) < abs(f1.first - power))
f1 = f2;
printf("%d %d\n", id, f1.second);
}
}
return 0;
}

E - priority queue练习题

題目

总时间限制: 2500ms 内存限制: 131072kB

描述

我们定义一个正整数a比正整数b优先的含义是:
*a的质因数数目(不包括自身)比b的质因数数目多;
*当两者质因数数目相等时,数值较大者优先级高。

现在给定一个容器,初始元素数目为0,之后每次往里面添加10个元素,每次添加之后,要求输出优先级最高与最低的元素,并把该两元素从容器中删除。

输入

第一行: num (添加元素次数,num <= 30)

下面10*num行,每行一个正整数n(n < 10000000).

输出

每次输入10个整数后,输出容器中优先级最高与最低的元素,两者用空格间隔。

样例输入

1
10 7 66 4 5 30 91 100 8 9

样例输出

66 5

解法

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
// http://cxsjsxmooc.openjudge.cn/
#include <stdio.h>
#include <set>
using namespace std;
int getPF(int n) {
int ret = 0;
for(int i = 2; i*i <= n; i++) {
if(n%i == 0) {
while(n /= i, n%i == 0);
ret++;
}
}
if(n != 1 && ret > 0) ret++;
return ret;
}
int main() {
for(int n; scanf("%d", &n) == 1;) {
multiset< pair<int, int> > S;
while(n--) {
for(int i = 0, x; i < 10; i++) {
scanf("%d", &x);
S.insert(make_pair(getPF(x), x));
}
multiset< pair<int, int> >::iterator it;
multiset< pair<int, int> >::iterator jt;
it = S.begin();
jt = S.end();
jt--;
printf("%d %d\n", (*jt).second, (*it).second);
S.erase(it);
S.erase(jt);
}
}
return 0;
}

X - 思考题最后一题,不计分,供测试

題目

总时间限制: 1000ms 内存限制: 65536kB

描述

请补齐下面程序,使得补齐后的程序,对于下面指定的输入数据,能产生指定的输出。
1
2
3
4
5
6
#include <iostream>
#include <string>
using namespace std;
template <class T>
class CMyistream_iterator
{

// 在此处补充你的代码

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
};
int main()
{
int t;
cin >> t;
while (t--) {
CMyistream_iterator<int> inputInt(cin);
int n1,n2,n3;
n1 = * inputInt;
int tmp = * inputInt;
cout << tmp << endl;
inputInt ++;
n2 = * inputInt;
inputInt ++;
n3 = * inputInt;
cout << n1 << "," << n2<< "," << n3 << ",";
CMyistream_iterator<string> inputStr(cin);
string s1,s2;
s1 = * inputStr;
inputStr ++;
s2 = * inputStr;
cout << s1 << "," << s2 << endl;
}
return 0;
}

输入

第一行是整数t,表示有t组数据。
每组数据由三个整数和两个字符串组成。整数都是小于220的正整数,字符串中间没有空格

输出

对每组输入数据,输出两行。
第一行是输入的第一个整数。
第二行依次输出输入的各项,用逗号","分隔。

样例输入

2
79 90 20 hello me
21 375 45 Jack good

样例输出

79
79,90,20,hello,me
21
21,375,45,Jack,good

解法

這裡要特別小心串流處理,這裡仍是用指針去維護。

Pointer Type(*) 和 Reference Type(&) 使用上也要明白差別。

  • 假使宣告 istream &mcin;
    一定要用 CMyistream_iterator(istream& m): mcin(m) 搭配 mcin >> front

    • 為什麼 mcin = m 不能取代 mcin(m) ?
      雖然我不太明白,但是 Reference Type 一定要在宣告的時候就決定取的位址,也就是說 mcin 再也不能跟動對應的位址,與指標不同的地方就在這裡。

      通常會這個寫來降低複雜度 int& ret = MAP[index]; 其中 ret 再也不能更動位址,當然也許再 C++11 之後的版本會有所不同。

  • 假使宣告 istream *mcin;
    彈性就很大,但使用時都要用 *mcin >> front

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>
using namespace std;
template <class T>
class CMyistream_iterator
{
public:
CMyistream_iterator(istream& m): mcin(&m) {
*mcin >> front;
}
void operator ++(int) {
*mcin >> front;
}
T operator * () {
return front;
}
private:
istream *mcin;
T front;
};
int main()
{
int t;
cin >> t;
while (t--) {
CMyistream_iterator<int> inputInt(cin);
int n1,n2,n3;
n1 = * inputInt;
int tmp = * inputInt;
cout << tmp << endl;
inputInt ++;
n2 = * inputInt;
inputInt ++;
n3 = * inputInt;
cout << n1 << "," << n2<< "," << n3 << ",";
CMyistream_iterator<string> inputStr(cin);
string s1,s2;
s1 = * inputStr;
inputStr ++;
s2 = * inputStr;
cout << s1 << "," << s2 << endl;
}
return 0;
}
Read More +

程序设计实习 MOOC Week 9 ABC

關於這一周

練習 STL 的語法。 題目來源

好久沒有練 C++ 程序,這是一個訓練 STL 的題單。

練習項目

std::list

  • list.merge(other_list)
    將 other_list 內容搬運到 list 後,other_list 清空。
  • list.sort()
    不依賴 std::sort, 自己內部有一個 sort()。
  • list.unique()
    跟另外一套的有點相似,一樣是要在排序後才能運行當作去重複。

std::set & std::multiset

  • insert()
  • find()
    查找,後回傳 set<>::iterator 的型態。
  • set<>::iterator
    begin()end() 的型態。
  • set<>::reverse_iterator
    rbegin()rend() 的型態。
  • erase()
    特別小心這個,傳入如果是 iterator 的話,就只會刪除單一元素,如果對於 multiset 來說,傳入一般的值(不是迭代器指針) 則會將所有相同的都刪除。

std::string

  • find(str [, start_pos])
    正向搜索 str 這個字串從 start_pos 開始算起。
  • rfind()
    逆向搜索 str 這個字串。
  • substr(start_post, sub_length)
    從某個位置開始,截出一段長度。

A - List

題目

总时间限制: 4000ms 内存限制: 65536kB

描述

写一个程序完成以下命令:
new id ——新建一个指定编号为id的序列(id<10000)
add id num——向编号为id的序列加入整数num
merge id1 id2——合并序列id1和id2中的数,并将id2清空
unique id——去掉序列id中重复的元素
out id ——从小到大输出编号为id的序列中的元素,以空格隔开

输入

第一行一个数n,表示有多少个命令( n <= 200000)。以后 n 行每行一个命令。

输出

按题目要求输出。

样例输入

16
new 1
new 2
add 1 1
add 1 2
add 1 3
add 2 1
add 2 2
add 2 3
add 2 4
out 1
out 2
merge 1 2
out 1
out 2
unique 1
out 1

样例输出

1 2 3 
1 2 3 4
1 1 2 2 3 3 4

1 2 3 4

解法

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
// http://cxsjsxmooc.openjudge.cn/
#include <stdio.h>
#include <algorithm>
#include <map>
#include <list>
using namespace std;
int main() {
for(int n; scanf("%d", &n) == 1; ) {
char cmd[10];
int id, num, aid;
map< int, list<int> > S;
while(n--) {
scanf("%s", cmd);
if(cmd[0] == 'n') { // new
scanf("%d", &id);
S[id] = list<int>();
} else if(cmd[0] == 'a') { // add
scanf("%d %d", &id, &num);
S[id].push_back(num);
} else if(cmd[0] == 'm') { // merge
scanf("%d %d", &id, &aid);
S[id].merge(S[aid]);
} else if(cmd[0] == 'u') { // unique
scanf("%d", &id);
S[id].sort();
S[id].unique();
} else { // out
scanf("%d", &id);
S[id].sort();
list<int>::iterator it, jt;
it = S[id].begin(), jt = S[id].end();
int f = 0;
for(; it != jt; it++) {
if(f) putchar(' ');
f = 1;
printf("%d", *it);
}
puts("");
}
}
}
return 0;
}

B - Set

題目

总时间限制: 5000ms 内存限制: 100000kB

描述

现有一整数集(允许有重复元素),初始为空。我们定义如下操作:
add x 把x加入集合
del x 把集合中所有与x相等的元素删除
ask x 对集合中元素x的情况询问
对每种操作,我们要求进行如下输出。
add 输出操作后集合中x的个数
del 输出操作前集合中x的个数
ask 先输出0或1表示x是否曾被加入集合(0表示不曾加入),再输出当前集合中x的个数,中间用空格格开。

输入

第一行是一个整数n,表示命令数。0<=n<=100000。
后面n行命令,如Description中所述。

输出

共n行,每行按要求输出。

样例输入

7
add 1
add 1
ask 1
ask 2
del 2
del 1
ask 1

样例输出

1
2
1 2
0 0
0
2
1 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
// http://cxsjsxmooc.openjudge.cn/
#include <stdio.h>
#include <algorithm>
#include <set>
using namespace std;
int main() {
for(int n, x; scanf("%d", &n) == 1;) {
char cmd[10];
multiset<int> S;
set<int> I;
while(n--) {
scanf("%s", cmd);
if(cmd[0] == 'a' && cmd[1] == 'd') { // add
scanf("%d", &x);
I.insert(x);
S.insert(x);
printf("%d\n", S.count(x));
} else if(cmd[0] == 'a' && cmd[1] == 's') { // ask
scanf("%d", &x);
printf("%d %d\n", I.find(x) != I.end(), S.count(x));
} else { // del
scanf("%d", &x);
printf("%d\n", S.count(x));
S.erase(x);
}
}
}
return 0;
}

C - 字符串操作

題目

总时间限制: 1000ms 内存限制: 65536kB

描述

给定n个字符串(从1开始编号),每个字符串中的字符位置从0开始编号,长度为1-500,现有如下若干操作:

    copy N X L:取出第N个字符串第X个字符开始的长度为L的字符串。
    add S1 S2:判断S1,S2是否为0-99999之间的整数,若是则将其转化为整数做加法,若不是,则作字符串加法,返回的值为一字符串。
    find S N:在第N个字符串中从左开始找寻S字符串,返回其第一次出现的位置,若没有找到,返回字符串的长度。
    rfind S N:在第N个字符串中从右开始找寻S字符串,返回其第一次出现的位置,若没有找到,返回字符串的长度。
    insert S N X:在第N个字符串的第X个字符位置中插入S字符串。
    reset S N:将第N个字符串变为S。
    print N:打印输出第N个字符串。
    printall:打印输出所有字符串。
    over:结束操作。

其中N,X,L可由find与rfind操作表达式构成,S,S1,S2可由copy与add操作表达式构成。

输入

第一行为一个整数n(n在1-20之间)

接下来n行为n个字符串,字符串不包含空格及操作命令等。

接下来若干行为一系列操作,直到over结束。

输出

根据操作提示输出对应字符串。

样例输入

3
329strjvc
Opadfk48
Ifjoqwoqejr
insert copy 1 find 2 1 2 2 2
print 2
reset add copy 1 find 3 1 3 copy 2 find 2 2 2 3
print 3
insert a 3 2
printall
over

样例输出

Op29adfk48
358
329strjvc
Op29adfk48
35a8

解法

這一題算是裡面最繁瑣的一題,一部分是因為其輸入的規則需要遞歸分析。
而為了實現遞歸分析,需要可以偷看輸入的下一個 token,因此先把每一個 token 切出來放在 queue 裏頭。

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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
// http://cxsjsxmooc.openjudge.cn/
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <sstream>
#include <queue>
#include <ctype.h>
using namespace std;
char s[32][512], lineStr[1024];
string str[32];
int strSize;
queue<string> tokenQ;
int str2num(string s) {
return atoi(s.c_str());
}
string num2str(int n) {
string s;
stringstream ss(s);
ss << n;
return ss.str();
}
int isValidNum(string s) {
int ret = 0;
for(int i = 0; i < s.length(); i++) {
if(!isdigit(s[i]))
return -1;
ret = ret * 10 + s[i] - '0';
if(ret > 99999)
return -1;
}
return ret;
}
string parsing() {
string p = tokenQ.front();
tokenQ.pop();
if(p == "copy") {
string N, X, L;
int n, x, l;
if(tokenQ.front() == "find" || tokenQ.front() == "rfind") {
N = parsing();
} else {
N = tokenQ.front(), tokenQ.pop();
}
if(tokenQ.front() == "find" || tokenQ.front() == "rfind") {
X = parsing();
} else {
X = tokenQ.front(), tokenQ.pop();
}
if(tokenQ.front() == "find" || tokenQ.front() == "rfind") {
L = parsing();
} else {
L = tokenQ.front(), tokenQ.pop();
}
n = str2num(N), x = str2num(X), l = str2num(L);
return str[n].substr(x, l);
} else if(p == "add") {
string S1, S2;
int s1, s2;
if(tokenQ.front() == "copy" || tokenQ.front() == "add") {
S1 = parsing();
} else {
S1 = tokenQ.front(), tokenQ.pop();
}
if(tokenQ.front() == "copy" || tokenQ.front() == "add") {
S2 = parsing();
} else {
S2 = tokenQ.front(), tokenQ.pop();
}
s1 = isValidNum(S1), s2 = isValidNum(S2);
if(s1 < 0 || s2 < 0)
return S1 + S2;
else
return num2str(s1 + s2);
} else if(p == "find") {
string S, N;
int s, n;
if(tokenQ.front() == "copy" || tokenQ.front() == "add") {
S = parsing();
} else {
S = tokenQ.front(), tokenQ.pop();
}
if(tokenQ.front() == "find" || tokenQ.front() == "rfind") {
N = parsing();
} else {
N = tokenQ.front(), tokenQ.pop();
}
n = str2num(N);
int pos = str[n].find(S);
if(pos != string::npos) {
return num2str(pos);
} else {
return num2str(str[n].length());
}
} else if(p == "rfind") {
string S, N;
int s, n;
if(tokenQ.front() == "copy" || tokenQ.front() == "add") {
S = parsing();
} else {
S = tokenQ.front(), tokenQ.pop();
}
if(tokenQ.front() == "find" || tokenQ.front() == "rfind") {
N = parsing();
} else {
N = tokenQ.front(), tokenQ.pop();
}
n = str2num(N);
int pos = str[n].rfind(S);
if(pos != string::npos) {
return num2str(pos);
} else {
return num2str(str[n].length());
}
} else if(p == "insert") {
string S, N, X;
int s, n, x;
if(tokenQ.front() == "copy" || tokenQ.front() == "add") {
S = parsing();
} else {
S = tokenQ.front(), tokenQ.pop();
}
if(tokenQ.front() == "find" || tokenQ.front() == "rfind") {
N = parsing();
} else {
N = tokenQ.front(), tokenQ.pop();
}
if(tokenQ.front() == "find" || tokenQ.front() == "rfind") {
X = parsing();
} else {
X = tokenQ.front(), tokenQ.pop();
}
n = str2num(N), x = str2num(X);
str[n].insert(x, S);
} else if(p == "reset") {
string S, N, X;
int s, n, x;
if(tokenQ.front() == "copy" || tokenQ.front() == "add") {
S = parsing();
} else {
S = tokenQ.front(), tokenQ.pop();
}
if(tokenQ.front() == "find" || tokenQ.front() == "rfind") {
N = parsing();
} else {
N = tokenQ.front(), tokenQ.pop();
}
n = str2num(N);
str[n] = S;
} else if(p == "print") {
string S, N, X;
int s, n, x;
if(tokenQ.front() == "find" || tokenQ.front() == "rfind") {
N = parsing();
} else {
N = tokenQ.front(), tokenQ.pop();
}
n = str2num(N);
printf("%s\n", str[n].c_str());
} else if(p == "printall") {
for(int i = 1; i <= strSize; i++)
printf("%s\n", str[i].c_str());
} else if(p == "over") {
}
return "";
}
int main() {
for(int n; scanf("%d", &n) == 1;) {
int N, X, L, S1, S2, S;
for(int i = 1; i <= n; i++) {
scanf("%s", s[i]);
str[i] = s[i];
}
strSize = n;
while(getchar() != '\n');
while(gets(lineStr)) {
stringstream sin(lineStr);
string token;
while(sin >> token)
tokenQ.push(token);
parsing();
}
}
return 0;
}
Read More +

a007. 判斷質數

題目

內容:

請判斷某數是否為質數

輸入說明:

輸入有多組測試資料(以EOF結尾),每組測試資料占一行,只包含一個整數x, 2 ≦ x ≦ 2147483647。

輸出說明:

對於每組測試資料,如果輸入的x為質數,則輸出一行「質數」(不含引號);否則輸出一行「非質數」(不含引號)。詳見範例測試資料。

範例輸入:

13
14

範例輸出:

質數
非質數

解法

  • 作法:
    Miller-Rabin Algorithm
a007.cpp
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
/**********************************************************************************/
/* Problem: a007 "判斷質數" */
/* Language: CPP (715 Bytes) */
/* Result: AC(0.2s, 224KB) judge by this@ZeroJudge */
/* Author: morris1028 at 2014-04-18 20:25:42 */
/**********************************************************************************/
#include<stdio.h>
#include<stdlib.h>
int Pow(long long x, int n, long long mod) {
long long Ans = 1, t = x;
while(n) {
if(n&1)
Ans *= t, Ans %= mod;
t *= t, t %= mod, n >>= 1;
}
return (int)Ans;
}
int JudgePrime(int n) {
if(n == 2 || n == 3) return 1;
if(n == 1) return 0;
if(!(n&1)) return 0;
int a, x, flag = 1, t;
for(a = 0; a < 2; a++) {
x = rand()%(n-4)+2;
t = Pow(x, n-1, n);
if(t != 1) return 0;
}
return 1;
}
int main() {
int n;
while(scanf("%d", &n) == 1) {
if(JudgePrime(n)) puts("質數");
else puts("非質數");
}
return 0;
}
Read More +

a576. No Cheating

題目

內容:

有個學校想辦一場考試,提供了 T 間教室。每間教室的座位都是 M×N 的矩陣(不同教室的 M, N 可以不一樣),而有的座位壞掉了不能坐。此外,為了避免學生作弊,如下圖,對任何一個學生而言,他的左方、左前方、右方、右前方都不可以有人坐。請問每間教室所能容納的學生數最多為何?

輸入說明:

第一行有一個數字 T,代表學校有 T 間教室。接下來會有每個教室的資料,每筆資料會有在同一行兩個正整數 M, N,代表座位的配置是 M×N。接下來的 M 行,每行有 N 個字元,’.’代表那個座位是好的,而’x’則代表那個座位壞了。

輸出說明:

對於每間教室,輸出”Case #X: Y”, 其中 X 代表這是第幾間教室,而 Y 則代表這間教室能容納的學生數最大值。

範例輸入:

4
2 3
...
...
2 3
x.x
xxx
2 3
x.x
x.x
10 10
....x.....
..........
..........
..x.......
..........
x...x.x...
.........x
...x......
........x.
.x...x....

範例輸出:

Case #1: 4
Case #2: 1
Case #3: 2
Case #4: 46

解法

  • 作法:
    按列黑白染色,會發現不能連的位置恰好可以化成二分圖,求最大獨立集即可。
    最大獨立集 = 點個數 - 最大匹配數
a576.cpp
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
133
134
135
136
137
138
139
140
141
142
143
144
/**********************************************************************************/
/* Problem: a576 "No Cheating" from GCJ 2008 Round 3 C */
/* Language: CPP (3826 Bytes) */
/* Result: AC(0.1s, 1.2MB) judge by this@ZeroJudge */
/* Author: morris1028 at 2014-04-18 18:09:46 */
/**********************************************************************************/
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <algorithm>
#include <queue>
#include <stack>
#include <set>
using namespace std;
struct Node {
int x, y, v;// x->y, v
int next;
} edge[65536];
int e, head[6500], prev[6500], record[6500];
int level[6500], visited[6500];
void addEdge(int x, int y, int v) {
edge[e].x = x, edge[e].y = y, edge[e].v = v;
edge[e].next = head[x], head[x] = e++;
edge[e].x = y, edge[e].y = x, edge[e].v = 0;
edge[e].next = head[y], head[y] = e++;
}
bool buildLevelGraph(int s, int t) {
memset(level, 0, sizeof(level));
queue<int> Q;
Q.push(s), level[s] = 1;
while(!Q.empty()) {
int tn = Q.front();
Q.pop();
for(int i = head[tn]; i != -1; i = edge[i].next) {
int y = edge[i].y;
if(edge[i].v > 0 && level[y] == 0) {
level[y] = level[tn] + 1;
Q.push(y);
}
}
}
return level[t] > 0;
}
int constructBlockingFlow(int s, int t) {
int ret = 0;
stack<int> stk;
memset(visited, 0, sizeof(visited));
stk.push(s);
while(!stk.empty()) {
int now = stk.top();
if(now != t) {
for(int i = head[now]; i != -1; i = edge[i].next) {
int y = edge[i].y;
if(visited[y] || level[y] != level[now] + 1)
continue;
if(edge[i].v > 0) {
stk.push(y), prev[y] = now, record[y] = i;
break;
}
}
if(stk.top() == now)
stk.pop(), visited[now] = 1;
} else {
int flow = 1e+9, bottleneck;
for(int i = t; i != s; i = prev[i]) {
int ri = record[i];
flow = min(flow, edge[ri].v);
}
for(int i = t; i != s; i = prev[i]) {
int ri = record[i];
edge[ri].v -= flow;
edge[ri^1].v += flow;
if(edge[ri].v == 0)
bottleneck = prev[i];
}
while(!stk.empty() && stk.top() != bottleneck)
stk.pop();
ret += flow;
}
}
return ret;
}
int maxflowDinic(int s, int t) {
int flow = 0;
while(buildLevelGraph(s, t))
flow += constructBlockingFlow(s, t);
return flow;
}
int main() {
int n, m;
int testcase, cases = 0;
int i, j, k, x, y;
char g[128][128];
int id[128][128];
scanf("%d", &testcase);
while(testcase--) {
e = 0;
memset(head, -1, sizeof(head));
scanf("%d %d", &n, &m);
for(int i = 0; i < n; i++)
scanf("%s", g[i]);
int ST[2] = {0, 0};
for(int i = 0; i < n; i++) {
for(int j = 0; j < m; j++) {
if(g[i][j] == '.') {
id[i][j] = ST[j&1]++;
} else {
id[i][j] = -1;
}
}
}
int source = ST[0] + ST[1];
int sink = source + 1;
for(int i = 0; i < ST[0]; i++)
addEdge(source, i, 1);
for(int i = 0; i < ST[1]; i++)
addEdge(i + ST[0], sink, 1);
int dx[] = {-1, -1, 0, 0, 1, 1};
int dy[] = {-1, 1, -1, 1, 1, -1};
int tx, ty, u, v;
for(int i = 0; i < n; i++) {
for(int j = 0; j < m; j += 2) {
if(id[i][j] == -1)
continue;
v = id[i][j];
for(int k = 0; k < 6; k++) {
tx = i + dx[k];
ty = j + dy[k];
if(tx < 0 || ty < 0 || tx >= n || ty >= m)
continue;
u = id[tx][ty];
if(u == -1)
continue;
addEdge(v, u + ST[0], 1);
}
}
}
int ret = maxflowDinic(source, sink);
printf("Case #%d: %d\n", ++cases, ST[0] + ST[1] - ret);
}
return 0;
}
Read More +

a858. 數三角形

題目

內容:

你有一個大小為N的完全圖,這N(N-1)/2條邊可能是紅色或黑色。任三個不同的點都形成一個三角形,請問三邊同色的三角形有幾個?

輸入說明:

第一行輸入一個正整數N,其中N<=1,000。接下來的N行,每行有N個數字,其中第i行的第j個數字代表邊(i,j)的顏色,紅色用1表示,黑色用2表示,i=j時則用0表示。

輸出說明:

請輸出同色三角形的數目。

範例輸入:

4
0 1 2 1
1 0 1 1
2 1 0 2
1 1 2 0

範例輸出:

1

解法

  • 作法:
    分治,將輸入 n 個劃分成兩堆,分別窮舉所有可能,採用合併的方式去運算。
a858.cpp
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
/**********************************************************************************/
/* Problem: a858 "數三角形" from */
/* Language: CPP (462 Bytes) */
/* Result: AC(0.1s, 264KB) judge by this@ZeroJudge */
/* Author: morris1028 at 2014-04-17 11:06:20 */
/**********************************************************************************/
#include <stdio.h>
int main() {
int n, x;
while (scanf("%d", &n) == 1) {
int p = (n) * (n-1) * (n-2) / 6;
int s = 0;
for (int i = 0; i < n; i++) {
int b = 0, r = 0;
for(int j = 0; j < n; j++) {
scanf("%d", &x);
r += x == 1;
b += x == 2;
}
s += r * b;
}
printf("%d\n", p - s/2);
}
return 0;
}
Read More +