2894 Arrange the Problem Set
2895 Cache Recommended
首先我们用1000大的cache,这样次数最少。
然后我们试着用更小的cache来达到同样的效果。
注意到对两个地址i和j,如果他们的request区间有overlap,那么所满足i % n == j % n的n就不能用作cache大小。
然后我们就把所有不合法的cache size标记,寻找最小的~
注意n == 0的时候输出0,-_-bbbbbbbb

CODE
1
// ZOJ Monthly, January 2008, Cache
2
// Written By FreePeter
3
4
#include <cstdio>
5
#include <cstring>
6
#include <iostream>
7
#include <algorithm>
8
9
using namespace std;
10
11
const int MaxN = 1000000 + 10;
12
pair<int, int> occur[1000];
13
int s[MaxN], n;
14
bool mark[1010];
15
16
void init();
17
void work();
18
void mark_factor(int x);
19
20
int main()
{
21
for (; scanf("%d", &n) != EOF; )
{
22
init();
23
work();
24
}
25
26
return 0;
27
}
28
29
void init()
{
30
fill(occur, occur + 1000, make_pair(n + 1, -1));
31
for (int i = 0; i < n; ++i)
{
32
scanf("%d", &s[i]);
33
occur[s[i]].first <?= i;
34
occur[s[i]].second >?= i;
35
}
36
}
37
38
void work()
{
39
if (n == 0)
{
40
cout << 0 << endl; return;
41
}
42
43
fill(mark, mark + 1010, false);
44
for (int i = 0; i < 1000; ++i)
45
for (int j = i + 1; j < 1000; ++j)
{
46
if (occur[i].second < occur[j].first || occur[j].second < occur[i].first) continue;
47
48
mark[1] = true; mark_factor(j - i);
49
}
50
51
int ans = 1;
52
for (; mark[ans]; ) ++ans;
53
cout << ans << endl;
54
}
55
56
void mark_factor(int x)
{
57
if (mark[x]) return;
58
mark[x] = true;
59
for (int i = 2; i * i <= x; ++i)
{
60
if (x % i) continue;
61
mark_factor(i); mark_factor(x / i);
62
}
63
}
64
65
66
2896 Common Factor Recommended
在一个素数域上考虑这个问题,那么他们的Common Factor可以通过GCD求出来。
然后测试一些大素数,如果都通过了就可以认为他们存在Common Factor了。
2897 Desmond's Ambition Recommended
首先求出所有的桥,如果将那些block视为一个点那么图就成为一棵树。
接下来分为4部分求:(建议自己想想,这个不太容易描述)
1. 每块内部的距离,暴力。
2. 每个桥被使用的次数,其实就是桥左边的顶点数*桥右边的顶点数,在DFS的时候顺便计算即可,参考Bridges
3. 每块内部的点对的最短路被经过的次数,对(u, v)点对来说,就是f(u)*f(v)*dist(u,v)
f(u)定义为,列举出所有一个顶点在u上的桥,在桥的令一端的顶点个数和。
4. 每块内部点通过某个点和外界联系的距离和。f(u) * sum_dist(u),sum_dist(u)是u到同一块内的其他所有点的最短距离和。

CODE
1
// ZOJ Monthly, January 2008, Desmond's Ambition
2
// Written By FreePeter
3
4
#include <cstdio>
5
#include <cstring>
6
#include <iostream>
7
#include <vector>
8
9
using namespace std;
10
11
const int MaxN = 10000 + 10, MaxEN = 100000 + 10;
12
struct EdgeNode
{
13
int p, len, id;
14
};
15
vector<EdgeNode> g[MaxN];
16
vector<EdgeNode> tree[MaxN];
17
vector<int> block[MaxN];
18
int n, m, color[MaxN], sum[MaxN], block_cnt;
19
long long ans;
20
long long f1[MaxN], f2[MaxN];
21
bool vis[MaxN], is_bridge[MaxEN];
22
int bridge[MaxEN], bridge_cnt;
23
int edge[MaxEN][3];
24
int low[MaxN], depth[MaxN], dfs_color[MaxN];
25
26
void init();
27
void work();
28
void dfs_bridge(int u, int fa, int deep);
29
void dfs_tree(int u, int fa);
30
void dfs_block(int u, int fa, int block_id);
31
void generate_block_dist(int idx);
32
long long gcd(long long a, long long b);
33
34
int main()
{
35
for (; scanf("%d%d", &n, &m) != EOF; )
{
36
init();
37
work();
38
}
39
return 0;
40
}
41
42
void init()
{
43
for (int i = 0; i < n; ++i)
{
44
g[i].clear(); tree[i].clear(); block[i].clear();
45
}
46
for (int i = 0; i < m; ++i)
{
47
int a, b, c;
48
scanf("%d%d%d", &a, &b, &c);
49
--a; --b;
50
EdgeNode tmp;
51
tmp.p = b; tmp.len = c; tmp.id = i;
52
g[a].push_back(tmp);
53
tmp.p = a;
54
g[b].push_back(tmp);
55
edge[i][0] = a; edge[i][1] = b; edge[i][2] = c;
56
}
57
}
58
59
void work()
{
60
// Generate all the bridges
61
fill(is_bridge, is_bridge + m, false);
62
fill(dfs_color, dfs_color + n, 0);
63
bridge_cnt = 0;
64
dfs_bridge(0, -1, 0);
65
66
// Generate all the blocks
67
fill(vis, vis + n, false);
68
block_cnt = 0;
69
for (int i = 0; i < n; ++i)
70
if (!vis[i])
{
71
dfs_block(i, -1, block_cnt);
72
++block_cnt;
73
}
74
75
// Generate the Tree
76
fill(f1, f1 + n, 0); fill(f2, f2 + n, 0);
77
for (int i = 0; i < bridge_cnt; ++i)
{
78
int eid = bridge[i];
79
int a = edge[eid][0], b = edge[eid][1], c = edge[eid][2];
80
int aa = color[a], bb = color[b];
81
EdgeNode tmp;
82
tmp.p = bb; tmp.len = c; tmp.id = eid;
83
tree[aa].push_back(tmp);
84
tmp.p = aa;
85
tree[bb].push_back(tmp);
86
87
// f1[a] += block[bb].size(); f1[b] += block[aa].size();
88
}
89
90
ans = 0;
91
// Part1, all the routes in the tree
92
dfs_tree(0, -1);
93
94
// Part2, all the internal routes
95
for (int i = 0; i < block_cnt; ++i)
96
generate_block_dist(i);
97
98
// Part3, merge
99
for (int i = 0; i < n; ++i)
100
ans += f1[i] * f2[i];
101
102
long long t1 = ans, t2 = n * (n - 1) / 2, d = gcd(t1, t2);
103
cout << t1 / d << "/" << t2 / d << endl;
104
}
105
106
void dfs_bridge(int u, int fa, int deep)
{
107
dfs_color[u] = 1;
108
depth[u] = deep; low[u] = deep;
109
110
for (vector<EdgeNode>::iterator it = g[u].begin(); it != g[u].end(); ++it)
{
111
if (it->p == fa) continue;
112
if (dfs_color[it->p] == 1)
{
113
low[u] <?= depth[it->p];
114
}
115
else if (dfs_color[it->p] == 0)
{
116
dfs_bridge(it->p, u, deep + 1);
117
low[u] <?= low[it->p];
118
if (low[it->p] > depth[u])
{
119
is_bridge[it->id] = true;
120
bridge[bridge_cnt++] = it->id;
121
}
122
}
123
}
124
125
dfs_color[u] = 2;
126
}
127
128
void dfs_tree(int u, int fa)
{
129
sum[u] = block[u].size();
130
131
for (vector<EdgeNode>::iterator it = tree[u].begin(); it != tree[u].end(); ++it)
{
132
if (it->p == fa) continue;
133
dfs_tree(it->p, u);
134
sum[u] += sum[it->p];
135
ans += static_cast<long long>(sum[it->p]) * (n - sum[it->p]) * it->len;
136
137
int eid = it->id;
138
int a = edge[eid][0], b = edge[eid][1];
139
int aa = color[a], bb = color[b];
140
if (aa == u)
{
141
f1[a] += sum[it->p]; f1[b] += n - sum[it->p];
142
}
143
else
{
144
f1[b] += sum[it->p]; f1[a] += n - sum[it->p];
145
}
146
147
148
}
149
}
150
151
void generate_block_dist(int idx)
{
152
int gg[30][30];
153
fill(gg[0], gg[block[idx].size()], 1000000000);
154
155
for (vector<int>::iterator it = block[idx].begin(); it != block[idx].end(); ++it)
{
156
int u = *it;
157
int uu = it - block[idx].begin();
158
for (vector<EdgeNode>::iterator eit = g[u].begin(); eit != g[u].end(); ++eit)
{
159
int v = eit->p;
160
if (color[v] != idx) continue;
161
int vv = find(block[idx].begin(), block[idx].end(), v) - block[idx].begin();
162
gg[uu][vv] = eit->len;
163
}
164
}
165
166
int n = block[idx].size();
167
for (int j = 0; j < n; ++j)
168
for (int i = 0; i < n; ++i)
169
for (int k = 0; k < n; ++k)
170
gg[i][k] <?= gg[i][j] + gg[j][k];
171
for (int i = 0; i < n; ++i)
{
172
long long &val = f2[block[idx][i]];
173
val = 0;
174
for (int j = 0; j < n; ++j)
175
if (j != i) val += gg[i][j];
176
}
177
178
for (int i = 0; i < n; ++i)
179
for (int j = i + 1; j < n; ++j)
{
180
ans += gg[i][j];
181
ans += static_cast<long long>(gg[i][j]) * f1[block[idx][i]] * f1[block[idx][j]];
182
}
183
184
}
185
186
void dfs_block(int u, int fa, int block_id)
{
187
color[u] = block_id; block[block_id].push_back(u);
188
vis[u] = true;
189
190
for (vector<EdgeNode>::iterator it = g[u].begin(); it != g[u].end(); ++it)
{
191
if ((!is_bridge[it->id]) && (!vis[it->p]))
192
dfs_block(it->p, u, block_id);
193
}
194
}
195
196
long long gcd(long long a, long long b)
{
197
return b == 0 ? a : gcd(b, a % b);
198
}
199
2898 Greedy Grave Robber
24个宝藏,搜12个,把他们的机关触发情况存入hash or map,然后搜右边12个,查表。
很经典的想法了。
2899 Hangzhou Tour
状态f[st][i][j], st表示已访问的顶点,i表示目前位置,j表示自行车位置,dp。
注意f[st][i][j]只可能转移到>=st的状态。有序性存在。
对相同的st的那些状态使用dijstra or SPFA.
2900 Icecream
dp, f[i][j][k] = 使用前i个icecream, 组成长度为j, 最后一个元素值为k的方案数。
复杂度2000 * 2000 * 100...10s够了。
2901 MV Maker Recommended
f[p][a][b] = 长度为2^p + 1, 第一个是a, 最后一个是b的最大value.
然后拼接~,复杂度O(n^3*logL)

CODE
1
// ZOJ Monthly, January 2008, MV Maker
2
// Written By FreePeter
3
4
#include <cstdio>
5
#include <cstring>
6
#include <iostream>
7
8
using namespace std;
9
10
const int MaxN = 100 + 10;
11
const long long INF = 1000000000000000LL;
12
long long f[20][MaxN][MaxN], g[2][MaxN];
13
14
int main()
{
15
int t;
16
cin >> t;
17
for (; t > 0; --t)
{
18
int n, l;
19
cin >> n >> l;
20
for (int i = 0; i < n; ++i)
21
for (int j = 0; j < n; ++j)
22
cin >> f[0][i][j];
23
24
--l;
25
26
int lev = 0;
27
for (int i = 0; (1 << (i + 1)) <= l; ++i)
{
28
for (int j = 0; j < n; ++j)
29
for (int k = 0; k < n; ++k)
{
30
f[i + 1][j][k] = -INF;
31
for (int x = 0; x < n; ++x)
32
f[i + 1][j][k] >?= f[i][j][x] + f[i][x][k];
33
}
34
++lev;
35
}
36
37
int cur = 0;
38
fill(g[cur], g[cur] + n, 0);
39
for (int i = lev; i >= 0; --i)
{
40
if (l < (1 << i)) continue;
41
l -= (1 << i);
42
43
cur = 1 - cur;
44
fill(g[cur], g[cur] + n, -INF);
45
for (int j = 0; j < n; ++j)
46
for (int k = 0; k < n; ++k)
47
g[cur][k] >?= g[1 - cur][j] + f[i][j][k];
48
}
49
50
cout << *max_element(g[cur], g[cur] + n) << endl;
51
}
52
return 0;
53
}
54
2902 Ten drops
模拟,注意这句
Of cause, a left click in grid without blob should be ignored because it's meaningless.
2895 Cache Recommended
首先我们用1000大的cache,这样次数最少。
然后我们试着用更小的cache来达到同样的效果。
注意到对两个地址i和j,如果他们的request区间有overlap,那么所满足i % n == j % n的n就不能用作cache大小。
然后我们就把所有不合法的cache size标记,寻找最小的~
注意n == 0的时候输出0,-_-bbbbbbbb
1
// ZOJ Monthly, January 2008, Cache 2
// Written By FreePeter3

4
#include <cstdio>5
#include <cstring>6
#include <iostream>7
#include <algorithm>8

9
using namespace std;10

11
const int MaxN = 1000000 + 10;12
pair<int, int> occur[1000];13
int s[MaxN], n;14
bool mark[1010];15

16
void init();17
void work();18
void mark_factor(int x);19

20

int main()
{21

for (; scanf("%d", &n) != EOF; )
{22
init();23
work();24
}25

26
return 0;27
}28

29

void init()
{30
fill(occur, occur + 1000, make_pair(n + 1, -1));31

for (int i = 0; i < n; ++i)
{32
scanf("%d", &s[i]);33
occur[s[i]].first <?= i;34
occur[s[i]].second >?= i;35
}36
}37

38

void work()
{39

if (n == 0)
{40
cout << 0 << endl; return;41
}42

43
fill(mark, mark + 1010, false);44
for (int i = 0; i < 1000; ++i)45

for (int j = i + 1; j < 1000; ++j)
{46
if (occur[i].second < occur[j].first || occur[j].second < occur[i].first) continue;47
48
mark[1] = true; mark_factor(j - i);49
}50

51
int ans = 1; 52
for (; mark[ans]; ) ++ans;53
cout << ans << endl;54
}55

56

void mark_factor(int x)
{57
if (mark[x]) return;58
mark[x] = true;59

for (int i = 2; i * i <= x; ++i)
{60
if (x % i) continue;61
mark_factor(i); mark_factor(x / i);62
}63
}64

65

66

2896 Common Factor Recommended
在一个素数域上考虑这个问题,那么他们的Common Factor可以通过GCD求出来。
然后测试一些大素数,如果都通过了就可以认为他们存在Common Factor了。
2897 Desmond's Ambition Recommended
首先求出所有的桥,如果将那些block视为一个点那么图就成为一棵树。
接下来分为4部分求:(建议自己想想,这个不太容易描述)
1. 每块内部的距离,暴力。
2. 每个桥被使用的次数,其实就是桥左边的顶点数*桥右边的顶点数,在DFS的时候顺便计算即可,参考Bridges
3. 每块内部的点对的最短路被经过的次数,对(u, v)点对来说,就是f(u)*f(v)*dist(u,v)
f(u)定义为,列举出所有一个顶点在u上的桥,在桥的令一端的顶点个数和。
4. 每块内部点通过某个点和外界联系的距离和。f(u) * sum_dist(u),sum_dist(u)是u到同一块内的其他所有点的最短距离和。
1
// ZOJ Monthly, January 2008, Desmond's Ambition2
// Written By FreePeter3

4
#include <cstdio>5
#include <cstring>6
#include <iostream>7
#include <vector>8

9
using namespace std;10

11
const int MaxN = 10000 + 10, MaxEN = 100000 + 10;12

struct EdgeNode
{13
int p, len, id;14
};15
vector<EdgeNode> g[MaxN];16
vector<EdgeNode> tree[MaxN];17
vector<int> block[MaxN];18
int n, m, color[MaxN], sum[MaxN], block_cnt;19
long long ans;20
long long f1[MaxN], f2[MaxN];21
bool vis[MaxN], is_bridge[MaxEN];22
int bridge[MaxEN], bridge_cnt;23
int edge[MaxEN][3];24
int low[MaxN], depth[MaxN], dfs_color[MaxN];25

26
void init();27
void work();28
void dfs_bridge(int u, int fa, int deep);29
void dfs_tree(int u, int fa);30
void dfs_block(int u, int fa, int block_id);31
void generate_block_dist(int idx);32
long long gcd(long long a, long long b);33

34

int main()
{35

for (; scanf("%d%d", &n, &m) != EOF; )
{36
init();37
work();38
}39
return 0;40
}41

42

void init()
{43

for (int i = 0; i < n; ++i)
{44
g[i].clear(); tree[i].clear(); block[i].clear();45
}46

for (int i = 0; i < m; ++i)
{47
int a, b, c;48
scanf("%d%d%d", &a, &b, &c);49
--a; --b;50
EdgeNode tmp;51
tmp.p = b; tmp.len = c; tmp.id = i;52
g[a].push_back(tmp);53
tmp.p = a;54
g[b].push_back(tmp);55
edge[i][0] = a; edge[i][1] = b; edge[i][2] = c;56
}57
}58

59

void work()
{60
// Generate all the bridges61
fill(is_bridge, is_bridge + m, false);62
fill(dfs_color, dfs_color + n, 0);63
bridge_cnt = 0;64
dfs_bridge(0, -1, 0);65

66
// Generate all the blocks67
fill(vis, vis + n, false);68
block_cnt = 0;69
for (int i = 0; i < n; ++i)70

if (!vis[i])
{71
dfs_block(i, -1, block_cnt);72
++block_cnt;73
}74

75
// Generate the Tree76
fill(f1, f1 + n, 0); fill(f2, f2 + n, 0);77

for (int i = 0; i < bridge_cnt; ++i)
{78
int eid = bridge[i];79
int a = edge[eid][0], b = edge[eid][1], c = edge[eid][2];80
int aa = color[a], bb = color[b];81
EdgeNode tmp;82
tmp.p = bb; tmp.len = c; tmp.id = eid;83
tree[aa].push_back(tmp);84
tmp.p = aa;85
tree[bb].push_back(tmp);86

87
// f1[a] += block[bb].size(); f1[b] += block[aa].size();88
}89

90
ans = 0;91
// Part1, all the routes in the tree92
dfs_tree(0, -1);93

94
// Part2, all the internal routes95
for (int i = 0; i < block_cnt; ++i)96
generate_block_dist(i);97

98
// Part3, merge99
for (int i = 0; i < n; ++i) 100
ans += f1[i] * f2[i];101

102
long long t1 = ans, t2 = n * (n - 1) / 2, d = gcd(t1, t2);103
cout << t1 / d << "/" << t2 / d << endl;104
}105

106

void dfs_bridge(int u, int fa, int deep)
{107
dfs_color[u] = 1;108
depth[u] = deep; low[u] = deep;109

110

for (vector<EdgeNode>::iterator it = g[u].begin(); it != g[u].end(); ++it)
{111
if (it->p == fa) continue;112

if (dfs_color[it->p] == 1)
{113
low[u] <?= depth[it->p];114
}115

else if (dfs_color[it->p] == 0)
{116
dfs_bridge(it->p, u, deep + 1);117
low[u] <?= low[it->p];118

if (low[it->p] > depth[u])
{119
is_bridge[it->id] = true;120
bridge[bridge_cnt++] = it->id;121
}122
}123
}124

125
dfs_color[u] = 2;126
}127

128

void dfs_tree(int u, int fa)
{129
sum[u] = block[u].size();130

131

for (vector<EdgeNode>::iterator it = tree[u].begin(); it != tree[u].end(); ++it)
{132
if (it->p == fa) continue;133
dfs_tree(it->p, u);134
sum[u] += sum[it->p];135
ans += static_cast<long long>(sum[it->p]) * (n - sum[it->p]) * it->len;136

137
int eid = it->id;138
int a = edge[eid][0], b = edge[eid][1];139
int aa = color[a], bb = color[b];140

if (aa == u)
{141
f1[a] += sum[it->p]; f1[b] += n - sum[it->p];142
}143

else
{144
f1[b] += sum[it->p]; f1[a] += n - sum[it->p];145
} 146
147

148
}149
}150

151

void generate_block_dist(int idx)
{152
int gg[30][30];153
fill(gg[0], gg[block[idx].size()], 1000000000);154

155

for (vector<int>::iterator it = block[idx].begin(); it != block[idx].end(); ++it)
{156
int u = *it;157
int uu = it - block[idx].begin();158

for (vector<EdgeNode>::iterator eit = g[u].begin(); eit != g[u].end(); ++eit)
{159
int v = eit->p;160
if (color[v] != idx) continue;161
int vv = find(block[idx].begin(), block[idx].end(), v) - block[idx].begin();162
gg[uu][vv] = eit->len;163
}164
}165

166
int n = block[idx].size();167
for (int j = 0; j < n; ++j)168
for (int i = 0; i < n; ++i)169
for (int k = 0; k < n; ++k)170
gg[i][k] <?= gg[i][j] + gg[j][k];171

for (int i = 0; i < n; ++i)
{172
long long &val = f2[block[idx][i]];173
val = 0;174
for (int j = 0; j < n; ++j)175
if (j != i) val += gg[i][j];176
}177

178
for (int i = 0; i < n; ++i)179

for (int j = i + 1; j < n; ++j)
{180
ans += gg[i][j];181
ans += static_cast<long long>(gg[i][j]) * f1[block[idx][i]] * f1[block[idx][j]];182
}183

184
}185

186

void dfs_block(int u, int fa, int block_id)
{187
color[u] = block_id; block[block_id].push_back(u);188
vis[u] = true;189

190

for (vector<EdgeNode>::iterator it = g[u].begin(); it != g[u].end(); ++it)
{191
if ((!is_bridge[it->id]) && (!vis[it->p])) 192
dfs_block(it->p, u, block_id);193
}194
}195

196

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

2898 Greedy Grave Robber
24个宝藏,搜12个,把他们的机关触发情况存入hash or map,然后搜右边12个,查表。
很经典的想法了。
2899 Hangzhou Tour
状态f[st][i][j], st表示已访问的顶点,i表示目前位置,j表示自行车位置,dp。
注意f[st][i][j]只可能转移到>=st的状态。有序性存在。
对相同的st的那些状态使用dijstra or SPFA.
2900 Icecream
dp, f[i][j][k] = 使用前i个icecream, 组成长度为j, 最后一个元素值为k的方案数。
复杂度2000 * 2000 * 100...10s够了。
2901 MV Maker Recommended
f[p][a][b] = 长度为2^p + 1, 第一个是a, 最后一个是b的最大value.
然后拼接~,复杂度O(n^3*logL)
1
// ZOJ Monthly, January 2008, MV Maker2
// Written By FreePeter3

4
#include <cstdio>5
#include <cstring>6
#include <iostream>7

8
using namespace std;9

10
const int MaxN = 100 + 10;11
const long long INF = 1000000000000000LL;12
long long f[20][MaxN][MaxN], g[2][MaxN];13

14

int main()
{15
int t;16
cin >> t;17

for (; t > 0; --t)
{18
int n, l;19
cin >> n >> l;20
for (int i = 0; i < n; ++i)21
for (int j = 0; j < n; ++j)22
cin >> f[0][i][j];23

24
--l;25
26
int lev = 0;27

for (int i = 0; (1 << (i + 1)) <= l; ++i)
{28
for (int j = 0; j < n; ++j)29

for (int k = 0; k < n; ++k)
{30
f[i + 1][j][k] = -INF;31
for (int x = 0; x < n; ++x)32
f[i + 1][j][k] >?= f[i][j][x] + f[i][x][k];33
}34
++lev;35
}36

37
int cur = 0;38
fill(g[cur], g[cur] + n, 0);39

for (int i = lev; i >= 0; --i)
{40
if (l < (1 << i)) continue;41
l -= (1 << i);42
43
cur = 1 - cur;44
fill(g[cur], g[cur] + n, -INF);45
for (int j = 0; j < n; ++j)46
for (int k = 0; k < n; ++k)47
g[cur][k] >?= g[1 - cur][j] + f[i][j][k];48
}49
50
cout << *max_element(g[cur], g[cur] + n) << endl;51
}52
return 0;53
}54

2902 Ten drops
模拟,注意这句
Of cause, a left click in grid without blob should be ignored because it's meaningless.




Comments
Write New Comment ▼
Write New Comment
Sorry! This knol's owner(s) have blocked you from editing, making suggestions, or commenting here.