[ACM 題目] 災難再臨

Description

Background

還記得那些年我們已經經歷的災難嗎?PTC201410D!ZJOI 2012 DAY2!如果不記得,接著請聽我捏造個故事。

Problem

危險種這一類的怪物,不斷地在村莊肆虐作亂,並且不斷地靠近帝國首都,艾斯德斯大人受令狩獵帝國周圍的危險種。

根據情報顯示,危險種移動的路徑預估為有向無環圖,牠們的數個巢穴坐落於地圖的末端 (也就是不會在有別的地點抵達這個地方),而在首都前將有數個要塞,要塞正牠們的目標之地。為了阻止牠們到來,身為艾斯德斯大人的下屬,必須派軍隊前往危險種前往要塞的必經之地,即使抵達的位置無法阻止所有巢穴的危險種,但能對艾斯德斯大人貢獻一份心力便已足夠。

由於必經之地很多,好不容易在地圖上標記起來,卻又不知道哪個地點比較好 (可以阻止最多巢穴前往要塞)。正在困擾的同時,艾斯德斯大人已經將全部危險種給剷除了 …

「還沒一瞬間就將怪物解決,艾斯德斯大人啊! <(_ _)>

不過報告書還是得寫 …

Input

輸入有多組測資。

每組測資第一行會有一個整數 N (N < 32767)。

接下來會有 N 行,第 i 行上會有數個整數 x,直到 0 表示結束,表示有一條邊從 i 到 x。

Output

對於每組測資,輸出可以埋伏地點以及埋伏的最佳收穫情況。

Sample Input

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
5
0
1 0
1 0
2 3 0
2 0
17
10 13 0
9 12 0
9 14 11 0
10 0
12 0
17 0
0
0
13 14 0
11 0
15 0
15 0
16 0
7 0
16 0
17 0
8 0

Sample Output

1
2
1 1
6 4

Solution

1
Read More +

UVa 12747 - Back to Edit Distance

Problem

目標從起始序列經過操作變成目標序列。

  • 操作 1 : 任意替除掉一個元素。
  • 操作 2 : 將元素插入到任意位置。

請問最少次數為何

Sample Input

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

Sample Output

1
2
Case 1: 2
Case 2: 6

Solution

很明顯地看出,任意插入就可以直接無視,只要找有最長共同子序列即可,剩餘的元素一次替除一次插入即可。

但是最長子序列在這一題無法使用 O(n * n) 的算法,因此將其轉換成 LIS 做法,由於元素恰好不重複,可以在 O(n log 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
#include <stdio.h>
#include <vector>
#include <algorithm>
using namespace std;
// LCS to LIS
int A[262144], B[262144];
int LIS(int A[], int n) {
vector<int> r;
r.push_back(A[0]);
for (int i = 1; i < n; i++) {
int pos = (int)(upper_bound(r.begin(), r.end(), A[i]) - r.begin());
if (pos == r.size())
r.push_back(A[i]);
else
r[pos] = A[i];
}
return r.size();
}
int main() {
int testcase, cases = 0;
int n, x;
scanf("%d", &testcase);
while (testcase--) {
scanf("%d", &n);
for (int i = 0; i < n; i++) {
scanf("%d", &x);
A[x] = i;
}
for (int i = 0; i < n; i++) {
scanf("%d", &x);
B[i] = A[x];
}
printf("Case %d: %d\n", ++cases, (n - LIS(B, n)) * 2);
}
return 0;
}
/*
2
5
1 3 5 4 2
1 5 4 3 2
4
1 2 4 3
3 4 2 1
*/
Read More +

UVa 12166 - Equilibrium Mobile

Problem

給一個天平表達式,請問至少要調整幾個權重才能使之平衡。

Sample Input

1
2
3
4
3
[[3,7],6]
40
[[2,3],[4,5]]

Sample Output

1
2
3
1
0
3

Solution

恰好是一棵二元樹,那麼可以得知道假使一個權重不改,最後的天平重量為何。
假使 depth 上的權重 w 不改,則最後的天平重量就是 w * pow(2, depth)。

藉此,可以記錄所有最後的天平重量,得知最多有多少不改 = 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
#include <stdio.h>
#include <string.h>
#include <vector>
#include <map>
using namespace std;
char exp[1048576];
map<long long, int> R;
void dfs(int l, int r, int dep) {
if (exp[l] == '[') {
int p = 0;
for (int i = l + 1; i <= r - 1; i++) {
if (exp[i] == '[') p++;
if (exp[i] == ']') p--;
if (p == 0 && exp[i] == ',') {
dfs(l+1, i-1, dep+1);
dfs(i+1, r-1, dep+1);
}
}
} else {
int w;
exp[r+1] = '\0';
sscanf(exp+l, "%d", &w);
R[(long long)w<<dep]++;
}
}
int main() {
int testcase;
scanf("%d", &testcase);
while (testcase--) {
scanf("%s", exp);
R.clear();
dfs(0, strlen(exp) - 1, 0);
int sum = 0, mx = 0;
for (map<long long, int>::iterator it = R.begin();
it != R.end(); it++)
sum += it->second, mx = max(mx, it->second);
printf("%d\n", sum - mx);
}
return 0;
}
/*
3
[[3,7],6]
40
[[2,3],[4,5]]
*/
Read More +

UVa 11724 - Evaluate the Expression

Problem

每個變數皆為正整數,給定一個算術表達式和變數之間的大小關係,請問最少產生出來的答案為何。

Sample Input

1
2
3
4
5
6
7
8
9
10
11
12
3
a+b*c
2
a>b
c>b
z*(x+y)
3
z>x
x>y
z>y
a+b+c+a
0

Sample Output

1
2
3
Case 1: 4
Case 2: 9
Case 3: 4

Solution

先使用 spfa 找到根據 greedy 策略分配的變數值,如果發生負環情況直接輸出 -1

然後使用矩陣鏈乘積的 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
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
#include <stdio.h>
#include <vector>
#include <queue>
#include <string.h>
#include <algorithm>
using namespace std;
char exp[1024], cond[1024];
int val[26];
int spfa(vector<int> g[]) {
queue<int> Q;
int inq[26] = {}, dist[26] = {};
int cnt[26] = {};
int u, v;
for (int i = 0; i < 26; i++) {
Q.push(i), dist[i] = 1;
}
while (!Q.empty()) {
u = Q.front(), Q.pop();
inq[u] = 0;
for (int i = 0; i < g[u].size(); i++) {
v = g[u][i];
if (dist[v] < dist[u] + 1) {
dist[v] = dist[u] + 1;
if (!inq[v]) {
inq[v] = 1, Q.push(v);
if (++cnt[v] > 26)
return 0;
}
}
}
}
for (int i = 0; i < 26; i++)
val[i] = dist[i];
return 1;
}
int used[512][512];
long long dp[512][512];
long long dfs(int l, int r) {
if (used[l][r])
return dp[l][r];
if (l == r)
return val[exp[l] - 'a'];
used[l][r] = 1;
long long &ret = dp[l][r];
ret = 1LL<<60;
int p = 0, test = 0;
for (int i = l; i <= r; i++) {
if (exp[i] == '(') p++;
if (exp[i] == ')') p--;
if (p == 0 && exp[i] == '+') {
ret = min(ret, dfs(l, i-1) + dfs(i+1, r));
test++;
}
if (p == 0 && exp[i] == '*') {
ret = min(ret, dfs(l, i-1) * dfs(i+1, r));
test++;
}
}
if (test == 0)
ret = min(ret, dfs(l+1, r-1));
return ret;
}
int main() {
int testcase, cases = 0;
int n;
scanf("%d", &testcase);
while (testcase--) {
scanf("%s", exp);
scanf("%d", &n);
vector<int> g[26];
for (int i = 0; i < n; i++) {
scanf("%s", cond);
g[cond[2]-'a'].push_back(cond[0]-'a');
}
printf("Case %d: ", ++cases);
if(!spfa(g)) {
puts("-1");
} else {
memset(used, 0, sizeof(used));
printf("%lld\n", dfs(0, strlen(exp) - 1));
}
}
return 0;
}
/*
3
a+b*c
2
a>b
c>b
z*(x+y)
3
z>x
x>y
z>y
a+b+c+a
0
*/
Read More +

UVa 1045 - The Great Wall Game

Problem

將棋子移動到可以形成萬里長城,也就是說移動到同一行、或同一列、或其一對角線上。

求移動得最少步數。

Sample Input

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

Sample Output

1
2
3
4
5
Board 1: 6 moves required.
Board 2: 0 moves required.
Board 3: 1 moves required.

Solution

窮舉要移動到哪裡,然後找完美匹配的最大權重 - KM 算法。

只要將移動步數弄成負權重套上去 KM 即可。

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
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
using namespace std;
struct KM {
int W[105][105], N;
int mx[105], my[105]; // match arr
int lx[105], ly[105]; // label arr
int x[105], y[105]; // used arr
int hungary(int nd) {
int i;
x[nd] = 1;
for(i = 0; i < N; i++) {
if(y[i] == 0 && W[nd][i] == lx[nd]+ly[i]) {
y[i] = 1;
if(my[i] == -1 || hungary(my[i])) {
my[i] = nd;
return 1;
}
}
}
return 0;
}
int run() {
int i, j, k, d;
memset(mx, -1, sizeof(mx));
memset(my, -1, sizeof(my));
for (int i = 0; i < N; i++)
lx[i] = -0x3f3f3f3f, ly[i] = 0;
for(i = 0; i < N; i++)
for(j = 0; j < N; j++)
lx[i] = lx[i] > W[i][j] ? lx[i] : W[i][j];
for(i = 0; i < N; i++) {
while(1) {
memset(x, 0, sizeof(x));
memset(y, 0, sizeof(y));
if(hungary(i)) break;
d = 0x3f3f3f3f;
for(j = 0; j < N; j++) {
if(x[j]) {
for(k = 0; k < N; k++)
if(!y[k])
d = d < lx[j]+ly[k]-W[j][k] ?
d : lx[j]+ly[k]-W[j][k];
}
}
if(d == 0x3f3f3f3f) break;
for(j = 0; j < N; j++) {
if(x[j]) lx[j] -= d;
if(y[j]) ly[j] += d;
}
}
}
int res = 0;
for(i = 0; i < N; i++) {
if(my[i] != -1)
res += W[my[i]][i];
}
return res;
}
} km;
int dist(int x1, int y1, int x2, int y2) {
return abs(x1 - x2) + abs(y1 - y2);
}
int main() {
int cases = 0;
int n, x[105], y[105];
while(scanf("%d", &n) == 1 && n) {
for (int i = 0; i < n; i++) {
scanf("%d %d", &x[i], &y[i]);
x[i]--, y[i]--;
}
km.N = n;
int ret = -0x3f3f3f3f;
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++)
for (int k = 0; k < n; k++)
km.W[j][k] = -dist(x[j], y[j], i, k);
ret = max(ret, km.run());
}
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++)
for (int k = 0; k < n; k++)
km.W[j][k] = -dist(x[j], y[j], k, i);
ret = max(ret, km.run());
}
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++)
km.W[j][i] = -dist(x[j], y[j], i, i);
}
ret = max(ret, km.run());
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++)
km.W[j][i] = -dist(x[j], y[j], i, n - i - 1);
}
ret = max(ret, km.run());
printf("Board %d: %d moves required.\n\n", ++cases, -ret);
}
return 0;
}
Read More +

UVa 12801 - Grandpa Pepe's Pizza

Problem

現在 pizza 上有 m 個橄欖,請問是否能均分 m 塊,使得每一塊皆有一個橄欖。

Sample Input

1
2
3
4
12 3
2 8 11
12 4
4 5 7 11

Sample Output

1
2
S
N

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
31
32
33
34
35
36
37
#include <stdio.h>
#include <algorithm>
using namespace std;
int main() {
int n, m, A[65536];
while (scanf("%d %d", &n, &m) == 2) {
for (int i = 0; i < m; i++)
scanf("%d", &A[i]);
A[m] = A[0] + n;
int ret = 0, div = n/m;
for (int i = A[0]; i < A[1]; i++) {
int d = i, ok = 1;
for (int j = 1; j <= m; j++) {
// printf("(%d %d] %d\n", d, d+div, A[j]);
if (d < A[j] && A[j] <= d + div)
d += div;
else {
ok = 0;
break;
}
}
// puts("");
if (ok) {
ret = 1;
break;
}
}
puts(ret ? "S" : "N");
}
return 0;
}
/*
12 3
2 8 11
12 4
4 5 7 11
*/
Read More +

UVa 12677 - Join two kingdoms

Problem

給兩棵樹,請問將兩個樹用一條邊連起來,則獲得新的一棵樹的最長路徑期望值為何。

Sample Input

1
2
3
4
5
6
7
8
9
10
11
12
13
14
4 5
1 2
2 3
4 2
2 3
3 4
4 1
4 5
1 5
1 2
2 3
3 4
4 5

Sample Output

1
2
5.350
4.400

Solution

利用 dp 方法,找到通過點 v 的 (以 v 為路徑端點)最長路徑為何,以及兩棵樹分別原有的最長路徑為何。

接著考量是否加入新一條會成為最長路徑,也就是說會通過新增加的邊。分別對每個樹的節點構成的最長路徑做排序,接著窮舉連接的點,用二分搜索找到另一個樹的節點,能夠使之成為更長的最長路徑。

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
#include <stdio.h>
#include <algorithm>
#include <vector>
#include <string.h>
#define oo 0xfffffff
using namespace std;
vector<int> g[65536];
int dp_down[65536][2], dp_up[65536];
int used[65536];
void dfs(int u) {
used[u] = 1;
dp_down[u][0] = dp_down[u][1] = 0;
for(int i = 0; i < g[u].size(); i++) {
int v = g[u][i];
if(used[v] == 0) {
dfs(v);
if(dp_down[v][0]+1 > dp_down[u][1])
dp_down[u][1] = dp_down[v][0] + 1;
if(dp_down[u][1] > dp_down[u][0])
swap(dp_down[u][0], dp_down[u][1]);
}
}
}
void dfs2(int u, int dep) {
dp_up[u] = dep, used[u] = 1;
for(int i = 0; i < g[u].size(); i++) {
int v = g[u][i];
if(used[v] == 0) {
int hv;
if(dp_down[v][0] + 1 != dp_down[u][0])
hv = dp_down[u][0];
else
hv = dp_down[u][1];
hv = max(hv, dp_up[u]);
dfs2(v, hv+1);
}
}
}
int main() {
int n, m;
int x, y;
while (scanf("%d %d", &n, &m) == 2) {
int mxpath[2][65636];
int a_diameter = 0, b_diameter = 0;
for (int i = 0; i <= n; i++)
g[i].clear();
for (int i = 1; i < n; i++) {
scanf("%d %d", &x, &y);
g[x].push_back(y);
g[y].push_back(x);
}
memset(used, 0, sizeof(used));
dfs(1);
memset(used, 0, sizeof(used));
dfs2(1, 0);
for (int i = 1; i <= n; i++) {
mxpath[0][i] = max(max(dp_down[i][0], dp_down[i][1]), dp_up[i]);
a_diameter = max(a_diameter, dp_down[i][0] + dp_down[i][1]);
a_diameter = max(a_diameter, dp_down[i][0] + dp_up[i]);
}
for (int i = 0; i <= m; i++)
g[i].clear();
for (int i = 1; i < m; i++) {
scanf("%d %d", &x, &y);
g[x].push_back(y);
g[y].push_back(x);
}
memset(used, 0, sizeof(used));
dfs(1);
memset(used, 0, sizeof(used));
dfs2(1, 0);
for (int i = 1; i <= m; i++) {
mxpath[1][i] = max(max(dp_down[i][0], dp_down[i][1]), dp_up[i]);
b_diameter = max(b_diameter, dp_down[i][0] + dp_down[i][1]);
b_diameter = max(b_diameter, dp_down[i][0] + dp_up[i]);
}
double ret = 0, suffix[65536] = {};
sort(mxpath[0]+1, mxpath[0]+1+n);
sort(mxpath[1]+1, mxpath[1]+1+m);
for (int i = m; i >= 0; i--)
suffix[i] = suffix[i+1] + mxpath[1][i];
int mx_diameter = max(a_diameter, b_diameter);
for (int i = 1, j = m; i <= n; i++) {
while (j > 0 && mxpath[0][i] + mxpath[1][j] >= mx_diameter)
j--;
ret += j * mx_diameter + (suffix[j + 1] + mxpath[0][i] * (m - j) + m - j);
}
printf("%.3lf\n", ret / n / m);
}
return 0;
}
/*
*/
Read More +

[ACM 題目] 學姊日談

Description

Background

某 M 正與學姊討論蘿莉控追小海女的故事。

某 M 喃喃自語 …
『用了暴力法來完成的話,就能在調整 O(1) - O(E[x]) 完成。』
『如果用一個最常見的樹鏈剖分來完成也不過是 O(log n) - O(log^2 n)』
『在一般情況下,詢問次數肯定比調整次數來得高,想一想常數還得加上去,完全贏不了啊。』

學姊在一旁說到
『那如果是單純的二元樹,有比較好做嗎?說不定有更簡化的算法來完成?』
『說不定那個 … bitvertor 還是 bitset 能完成呢。』
『這個想法難不成是找到 lowbit 嗎?我沒有暫時想法。』某 M 這麼回答道。
『也許吧 … 我也不確定』學姊簇著眉。

某 M 發了瘋似的想了一個算法
『如果我們將其轉換成 k-ary search tree,也就是說需要將節點編號重新編成有大小關係,然後維護一個 BST 來查找 lower_bound 的結果,這麼一來就是 O(k log n) - O(log n) 了!』
『啊啊啊,這個方法不可行,』
學姊將鄙視般的眼神投向某 M。看來這場病還要持續很久。

『將題目弄成找樹前綴和好了,既然暴力法有期望值的剪枝,讓它剪不了不就好了!』
『你覺得不會被其他解法坑殺嗎 …』學姊如此擔憂地表示到。
『沒關係,吾等 M 可不是說假的』

Problem

給定一棵樹,樹根 root 編號 0,每個點一開始的權重為 0。

操作 x k: 將節點 x 的權重增加 k,請輸出從 x 到 root 的權重和。

Input

輸入有多組測資,每組測資第一行會有一個整數 N (N < 32767),表示這棵樹有多少個節點。

接下來會有 N - 1 行,每一行上會有兩個整數 u, v (0 <= u, v < N) 表示 u, v 之間有一條邊。

接下來會有一行上有一個整數 Q (Q < 32767),表示接下來有 M 組詢問。

Output

對於每個詢問結果輸出一行,請參照範例輸出的說明。

每組測資後空一行。

Sample Input

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
10
0 1
0 2
1 3
0 4
3 5
4 6
5 7
5 8
4 9
5
1 1
5 2
3 0
0 4
4 8

Sample Output

1
2
3
4
5
1
3
1
4
12

More

名為 “學姊”。

Solution

1
Read More +

[ACM 題目] 計畫巧遇

Description

Background

正陷入暗戀的蘿莉控,對象正是那小海女 “能年犬”,為了與其相遇,做了一個情報偵測器,但總不能刻意繞道去相遇,這顯然會相當接近跟蹤狂。根據情報網顯示,地圖將會長得跟樹狀圖一樣,接著會有一連串的消息顯示小海女疑似出現的地方,同時也會被驗證是假消息。

能年犬

蘿莉控只想知道如果從 x 點回到家的路上,有沒有機會遇到小海女。如果事先知道將會在哪個場所相遇,就能事先準備。接下來就請你協助他了!

Problem

給定一棵樹,樹根編號 0,每個點一開始的權重為 0,操作有以下兩種。

操作 M x : 將節點 x 的權重從 0->1 或者 1->0。
操作 S x : 輸出從 x 到 root 路徑上,第一個權重為 1 的節點編號。

Input

輸入有多組測資,每組測資第一行會有一個整數 N (N < 32767),表示這棵樹有多少個節點。

接下來會有 N - 1 行,每一行上會有兩個整數 u, v (0 <= u, v < N) 表示 u, v 之間有一條邊。

接下來會有一行上有一個整數 Q (Q < 32767),表示接下來有 M 組詢問。

Output

對於每個詢問結果輸出一行,請參照範例輸出的說明。

每組測資後空一行。

Sample Input

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
10
0 1
0 2
1 3
0 4
3 5
4 6
5 7
5 8
4 9
10
M 1
S 8
S 4
M 0
M 7
M 9
S 5
M 3
M 8
S 5
31
0 1
0 2
0 3
1 4
1 5
2 6
2 7
3 8
4 9
4 10
4 11
6 12
6 13
12 14
12 15
13 16
13 17
14 18
14 19
14 20
17 21
17 22
20 23
21 24
21 25
22 26
22 27
23 28
24 29
24 30
10
M 6
S 29
S 9
M 0
S 9
S 6
S 2
M 6
S 29
S 6

Sample Output

1
2
3
4
5
6
7
8
9
10
11
12
1
-1
1
3
6
-1
0
6
0
0
0

Solution

1
Read More +

UVa 12793 - Confederation

Problem

在三維空間中劃分區域,給定 N 個平面,對於每一個點而言形成 N-tuple 的資訊 (0/1 左側、右側)。請問哪一個 N-tuple 具有最多點,輸出最多的點個數即可。

Sample Input

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2 5
1 0 0 1
2 0 0 8
0 1 0
2 2 2
3 3 3
5 5 5
2 18 4
4 8
0 0 1 1
1 0 1 2
-1 1 1 3
-1 -1 1 3
0 0 5
0 0 4
0 0 -2
1 0 5
40 19 104
13 26 84
89 -45 18
3 1 0

Sample Output

1
2
3
5

Solution

直接將平面帶入每一個點,得到 N-tuple 資訊,接著對這個資訊做 RS hash 下,直接壓 int 去做 count,這樣會快於 map<string, int>

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 <stdio.h>
#include <map>
#include <algorithm>
using namespace std;
int main() {
int n, m, x, y, z;
int A[512], B[512], C[512], D[512];
while (scanf("%d %d", &n, &m) == 2) {
for (int i = 0; i < n; i++)
scanf("%d %d %d %d", A+i, B+i, C+i, D+i);
map<unsigned int, int> R;
for (int i = 0; i < m; i++) {
scanf("%d %d %d", &x, &y, &z);
unsigned int a = 63689, b = 378551;
unsigned int value = 0;
for (int j = 0; j < n; j++) {
if (A[j] * x + B[j] * y + C[j] * z > D[j])
value = value * a + 1;
else
value = value * a + 0;
a *= b;
}
R[value]++;
}
int ret = 0;
for (map<unsigned int, int>::iterator it = R.begin();
it != R.end(); it++)
ret = max(ret, it->second);
printf("%d\n", ret);
}
return 0;
}
/*
*/
Read More +