20161107测试总结

这次测试在比打暴力…

T1

此题体现了SPFA的性能很差…

30分

题解表示随便什么暴力…

60分

暴力连边+堆优化dijkstra,使用SPFA就233了…

100分

考虑建边,此题建边简直就是建网络流的图跑最短路…
对于每个板块,我们建一个超级源 $s$,板块中每个点向 $s$ 连代价为 $0$ 的边,$s$ 向板块中每个点连代价为 $c_i$ 的边。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
#include <cctype>
#include <cstdio>
#include <algorithm>
#include <iostream>
#include <vector>
#include <cstring>
#include <climits>
#include <queue>
#include <ctime>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/priority_queue.hpp>
using namespace std;
const int iol = 1024 * 1024;
char iobuf[iol], *ioh, *iot, ioc;
inline char read() {
if(ioh == iot) {
iot = (ioh = iobuf) + fread(iobuf, 1, iol, stdin);
if(ioh == iot) return -1;
}
return *ioh++;
}
template<class T>
inline void read(T& x) {
for(ioc = read(); !isdigit(ioc); ioc = read());
x = 0;
for(; isdigit(ioc); ioc = read())
x = (x << 1) + (x << 3) + (ioc ^ '0');
}
const int MAXN = 5000011;
struct Node {
int v;
long long w;
Node() {}
Node(int v, long long w) : v(v), w(w) {}
inline bool operator < (const Node &n) const {
return w > n.w;
}
};
vector<Node> edge[MAXN];
inline void addEdge(int u, int v, long long w) {
edge[u].push_back(Node(v, w));
edge[v].push_back(Node(u, 0));
}
int n, m;
bool vis[MAXN];
long long dis1[MAXN], disn[MAXN];
const long long INF = LONG_LONG_MAX >> 1;
typedef __gnu_pbds::priority_queue<Node> Heap;
Heap::point_iterator id[MAXN];
inline void dijkstra(int s, long long *dis) {
fill(dis + 1, dis + n + m + 1, INF);
memset(vis, 0, sizeof(bool) * (n + m + 1));
memset(id, 0, sizeof(id));
dis[s] = 0;
Heap q;
id[s] = q.push(Node(s, 0));
while (!q.empty()) {
register int now = q.top().v;
q.pop();
if (vis[now]) continue;
vis[now] = 1;
for (int i = 0; i < edge[now].size(); i++) {
Node *x = &edge[now][i];
if (x->w + dis[now] < dis[x->v]) {
dis[x->v] = x->w + dis[now];
if (id[x->v] != NULL) q.modify(id[x->v], Node(x->v, dis[x->v]));
else id[x->v] = q.push(Node(x->v, dis[x->v]));
}
}
}
}
int main() {
#ifndef ONLINE_JUDGE
freopen("farm.in", "r", stdin);
#endif
read(n), read(m);
for (int i = 1, w, ni; i <= m; i++) {
read(w), read(ni);
for (int j = 0, v; j < ni; j++) read(v), addEdge(v, n + i, w);
}
dijkstra(1, dis1);
dijkstra(n, disn);
long long tmp = INF;
for (int i = 1; i <= n; i++)
tmp = min(tmp, max(dis1[i], disn[i]));
if (tmp == INF) cout << "impossible", exit(0);
cout << tmp << "\n";
for (int i = 1; i <= n; i++)
if (max(dis1[i], disn[i]) == tmp)
cout << i << " ";
return 0;
}

T2

30分

暴力枚举并检测…

100分

由于 $0 \leqslant x \leqslant 10^9$ 很小,若 $y > 10^{10}$ 时显然 $x \geq 0$。所以取模明显是逗你的。

设 $y = \overline{a_9a_8a_7a_6a_5a_4a_3a_2a_1a_0}$,则我们可以得到

$x = f_{y,k}-y=\sum\limits_{i=0}^{9}a_{i}^{k}-\sum\limits_{i=0}^{9}a_{i}\times 10^i=\sum\limits_{i=0}^{9}a_i(a_i^{k-1}-10^i)$,我们发现其实就是有多少种可能的 $a_9a_8a_7a_6a_5a_4a_3a_2a_1a_0$ 的组合满足条件,就是一个搜索问题。但是这个复杂度还是 $O(10^{10})$ 的,但是我们可以折半搜索。因为这个搜索满足可并性(即对于某个固定的 $x$,如果我们搜索了 $a_4a_3a_2a_1a_0$ 的结果,我们就可以知道 $a_9a_8a_7a_6a_5$ 的结果,即 $x-g(a_4a_3a_2a_1a_0)$,我们可以将 $a_9a_8a_7a_6a_5$ 的搜索结果存入哈希表中,搜索 $a_4a_3a_2a_1a_0$ 去查找哈希表),复杂度降至 $O(10^5)$。

由于 $k$ 较小,我们可以预处理些结果来降低常数,这样你就可以过 $100$ 分了。

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
#include <cctype>
#include <cstdio>
#include <algorithm>
#include <iostream>
#include <vector>
#include <cstring>
#include <climits>
#include <queue>
#include <cassert>
using namespace std;
#define inline inline __attribute__((optimize("O3")))
bool iosig;
char ch;
const int sig = 233;
const int HashSize = 2333323;
struct HashMap {
struct Element {
int k;
long long sum;
int cnt;
};
Element h[HashSize + 1000];
inline void put(int k, long long sum) {
register int now = (sum + k * sig) % HashSize;
if (now < 0)
now += HashSize;
while (true) {
if (!h[now].k) {
h[now].k = k, h[now].sum = sum, h[now].cnt = 1;
return;
}
else if (h[now].sum == sum && h[now].k == k) {
h[now].cnt++;
return;
}
now++;
if (now >= HashSize)
now -= HashSize;
}
}
inline int get(int k, long long sum) {
register int now = (sum + k * sig) % HashSize;
if (now < 0)
now += HashSize;
while (true) {
if (!h[now].k) return 0;
else if (h[now].sum == sum && h[now].k == k) return h[now].cnt;
now++;
if (now >= HashSize)
now -= HashSize;
}
}
};
template<class T>
inline void read(T &x) {
x = 0, iosig = 0;
do {
ch = getchar();
if (ch == '-') iosig = 1;
} while (!isdigit(ch));
while (isdigit(ch)) x = (x << 1) + (x << 3) + (ch ^ '0'), ch = getchar();
if (iosig) x = -x;
}
HashMap h;
typedef long long ll;
const int MAXN = 15;
const int MAXM = 100010;
int powVal[MAXN][MAXN];
int T, X, K;
ll num[15][MAXM], tot[MAXM];
inline void dfs1(int k, int now, ll sum) {
if (now <= 4) {
h.put(k, sum);
return;
}
for (int i = 0; i < 10; ++i)
dfs1(k, now - 1, sum - (ll)i * (ll)(powVal[10][now] - powVal[i][k - 1]));
}
inline void dfs2(int now, ll sum) {
if (now < 0) {
num[K][++tot[K]] = sum;
return;
}
for (int i = 0; i < 10; ++i)
dfs2(now - 1, sum - (ll)i * (ll)(powVal[10][now] - powVal[i][K - 1]));
}
inline void init() {
for (int i = 1; i <= 10; i++) {
powVal[i][0] = 1;
for (int j = 1; j < 10; j++)
powVal[i][j] = powVal[i][j - 1] * i;
}
for (int k = 1; k <= 9; ++k) dfs1(k, 9, 0);
for (K = 1; K <= 9; K++)
dfs2(4, 0), sort(num[K] + 1, num[K] + 100001);
}
int main() {
#ifndef ONLINE_JUDGE
freopen("number.in", "r", stdin);
#endif
read(T);
init();
while (T--) {
read(X), read(K);
register int ans = 0;
for (int i = 1, j; i <= 100000; ++i) {
for (j = i; j <= 100000 && num[K][j] == num[K][i]; j++);
ans += (j - i) * h.get(K, X - num[K][i]), i = j - 1;
}
cout << ans << "\n";
}
return 0;
}

T3

100分

由于距离最远的野猪是一定要花该距离的代价打的,我们可以枚举最远的野猪应该在
哪个时间点打死。对于 $[l, r]$ 这段时间段内出现的野猪(注意,此处的野猪是严格在此区间出现的野猪),假设我们在 $t$ 这个时间把最远的野猪打死,假设距离为 $D$,之后我们就需要处理 $[l, t-1]$ 与 $[t + 1, r]$ 的野猪。用 $f_{l,r}$ 表示杀死严格出现在 $[l,r]$ 时间段内野猪所需要的最小代价,则 $f_{l,r} = \min(f_{l,t-1} + f_{t+1,r}) + D$ 用记忆化搜索实现就可以了。但是由于区间长度很长,所以需要离散化。时间复杂度$O(n^3)$。

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
#include <cctype>
#include <cstdio>
#include <algorithm>
#include <iostream>
#include <vector>
#include <cstring>
#include <climits>
#include <queue>
using namespace std;
char ch;
bool iosig;
template<class T>
inline void read(T &x) {
x = 0, iosig = 0;
do {
ch = getchar();
if (ch == '-') iosig = true;
} while (!isdigit(ch));
while (isdigit(ch)) x = (x << 1) + (x << 3) + (ch ^ '0'), ch = getchar();
if (iosig) x = -x;
}
struct Pig {
int l, r, d;
inline bool operator < (const Pig &n) const {
return d > n.d;
}
} pigs[310];
struct Data {
int v;
int num;
bool operator < (const Data &n) const {
return v < n.v;
}
} data[610];
bool vis[310];
int n, cnt, f[610][610];
int dfs(int l, int r, int cur) {
if (l > r) return 0;
if (f[l][r] != INT_MAX) return f[l][r];
int i;
for (i = cur; i <= n; ++i) if (l <= pigs[i].l && pigs[i].r <= r) {cur = i; break;}
if (i == n + 1) {f[l][r] = 0; return 0;}
for (i = pigs[cur].l; i <= pigs[cur].r; ++i)
f[l][r] = min(f[l][r], dfs(l, i - 1, cur + 1) + dfs(i + 1, r, cur + 1));
f[l][r] += pigs[cur].d;
return f[l][r];
}
int main() {
#ifndef ONLINE_JUDGE
freopen("wild.in","r",stdin);
#endif
read(n);
for (register int i = 1; i <= n; ++i) {
read(pigs[i].l), read(pigs[i].r), read(pigs[i].d);
data[i].v = pigs[i].l, data[i].num = i, data[i + n].v = pigs[i].r, data[i + n].num = i;
}
stable_sort(data + 1, data + (n << 1 | 1));
data[0].v = data[1].v - 1;
for (register int i = 1; i <= (n << 1); ++i) {
if (data[i].v != data[i - 1].v) cnt++;
if (!vis[data[i].num]) {
vis[data[i].num] = true;
pigs[data[i].num].l = cnt;
}
else pigs[data[i].num].r = cnt;
}
stable_sort(pigs + 1, pigs + n + 1);
for (register int i = 0; i <= cnt; ++i) fill(f[i], f[i] + cnt + 1, INT_MAX);
cout << dfs(1, cnt, 1) << "\n";
return 0;
}

Comments

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×