20161105测试总结

T1

直接贪心,对输入数据排序,每次选价格最高的三本书进行购买即可,因为只有这样才能取到能免费的书中最贵的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <cctype>
#include <cstdio>
#include <algorithm>
#include <iostream>
using namespace std;
char ch;
bool iosig;
inline void read(int &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;
}
int n, w[100005];
long long ans;
int main() {
read(n);
for (int i = 1; i <= n; i++) read(w[i]);
sort(w + 1, w + n + 1);
int res = n % 3;
for (int i = 1 + res; i <= n; i += 3) ans += w[i + 1] + w[i + 2];
if (res == 1) ans += w[1];
else if (res == 2) ans += w[1] + w[2];
cout << ans;
return 0;
}

T2

离考试结束还有10min时推出此题的我表示…
此题就是组合,我们可以从小的数据手算发现一下规律,一种是一个递归的多项式(我最后才推出来的),另一种即题解,只需$O(n)$预处理阶乘,那么就可以$O(1)$得到任意组合数,递归实现时间复杂度为$O(n^2)$,但递归会暴栈,可以考虑用FFT,时间复杂度$O(n \log n)$,编程复杂度就2333了…
下面说一下题解,我们可以$O(n^2)$预处理可能用到的所有组合数,用$f[i][j]$表示第 $i$ 行,和为 $j$ 的方案数,转移时用前缀和优化,时间复杂度$O(n^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
37
38
39
40
41
42
43
44
45
46
47
48
49
#include <iostream>
#include <cstdio>
#include <cctype>
#include <cmath>
#include <cstring>
using namespace std;
char ch;
bool iosig;
inline void read(int &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;
}
const int MOD = 1e9;
const int MAXN = 2010 * 2;
int c[MAXN][MAXN], f[MAXN][MAXN];
int n, m;
typedef long long ll;
inline void mod(int &a) {
if (a >= MOD) a -= MOD;
}
inline void solve() {
read(n), read(m);
memset(f, 0, sizeof(f));
for (int i = 0; i <= m; i++) f[0][i] = 1;
for (int i = 1; i <= n; i++) {
for (int j = 0; j <= m; j++) {
int cur = f[i - 1][j];
cur = ((ll)cur * c[j + m - 1][m - 1]) % MOD;
f[i][j] = j ? f[i][j - 1] + cur : cur;
mod(f[i][j]);
}
}
cout << f[n][m] << "\n";
}
int main() {
int t;
for (int i = 0; i <= 4000; i++) c[i][0] = c[i][i] = 1;
for (int i = 2; i <= 4000; i++)
for (int j = 1; j < i; j++)
c[i][j] = c[i - 1][j] + c[i - 1][j - 1], mod(c[i][j]);
read(t);
while (t--) solve();
return 0;
}

T3

看到此题想虚树的我就挂掉了…
我们先考虑贪心,当我们已经确定了两个节点之后,那么最短路一定是两个节点先分别上升到同一高度,然后在沿中间的边走过去,只需要枚举两个节点向上跳到哪一层就好。
我们可以考虑把向左儿子走看成 $0$,向右儿子走看成 $1$,那么每一个节点就对应了一个二进制数,水平移动就对应加减一,可以用线段树维护,故时间复杂度为$O(nlogn)$

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
#include <bits/stdc++.h>
using namespace std;
const int MaxN = 100010, MaxT = 1 << 18;
struct Tree_node {
int lazy, sum, len;
} tree[MaxT];
int s[MaxN], t[MaxN], sn, tn;
inline void build(int l, int r, int now) {
tree[now].len = r - l + 1;
tree[now].lazy = tree[now].sum = 0;
if (l == r) return;
int mid = (l + r) >> 1;
build(l, mid, now << 1);
build(mid + 1, r, now << 1 | 1);
}
inline void addLazy(int now, int lazy) {
tree[now].lazy = lazy;
tree[now].sum = (lazy - 1) * tree[now].len;
}
inline void pushDown(int now) {
if (tree[now].lazy) {
addLazy(now << 1, tree[now].lazy);
addLazy(now << 1 | 1, tree[now].lazy);
tree[now].lazy = 0;
}
}
inline void update(int now) {
tree[now].sum = tree[now << 1].sum + tree[now << 1 | 1].sum;
}
inline void modify(int l, int r, int now, int x, int y, int z) {
if (r < x || y < l) return;
if (x <= l && r <= y) return addLazy(now, z);
int mid = (l + r) >> 1;
pushDown(now);
modify(l, mid, now << 1, x, y, z);
modify(mid + 1, r, now << 1 | 1, x, y, z);
update(now);
}
inline int queryL(int l, int r, int now, int x) {
if (x < l) return 0;
if (tree[now].sum == tree[now].len) return 0;
if (l == r) return (tree[now].sum == 0) ? l : 0;
int mid = (l + r) >> 1;
pushDown(now);
int ret = queryL(mid + 1, r, now << 1 | 1, x);
if (!ret) ret = queryL(l, mid, now << 1, x);
return ret;
}
inline int queryR(int l, int r, int now, int x) {
if (x < l) return 0;
if (tree[now].sum == 0) return 0;
if (l == r) return (tree[now].sum == 1) ? l : 0;
int mid = (l + r) >> 1;
pushDown(now);
int ret = queryR(mid + 1, r, now << 1 | 1, x);
if (!ret) ret = queryR(l, mid, now << 1, x);
return ret;
}
inline void treeExport(int l, int r, int now, int x, int *p) {
if (l > x) return;
if (l == r) {
p[l] = tree[now].sum;
return;
}
int mid = (l + r) >> 1;
pushDown(now);
treeExport(l, mid, now << 1, x, p);
treeExport(mid + 1, r, now << 1 | 1, x, p);
}
inline void init(int *p, int &n) {
static char s[MaxN];
scanf("%s", s + 1);
int max = strlen(s + 1);
build(1, max, 1);
n = 0;
for (int i = 1; i <= max; ++i) {
if (s[i] == '1') {
++n;
modify(1, max, 1, n, n, 1);
} else if (s[i] == '2') {
++n;
modify(1, max, 1, n, n, 2);
} else if (s[i] == 'U') --n;
else if (s[i] == 'L') {
int pos = queryR(1, max, 1, n);
modify(1, max, 1, pos + 1, n, 2);
modify(1, max, 1, pos, pos, 1);
} else if (s[i] == 'R') {
int pos = queryL(1, max, 1, n);
modify(1, max, 1, pos + 1, n, 1);
modify(1, max, 1, pos, pos, 2);
}
}
treeExport(1, max, 1, n, p);
}
int main() {
#ifndef ONLINE_JUDGE
freopen("board.in", "r", stdin);
#endif
init(s, sn);
init(t, tn);
register int sum = abs(sn - tn);
register int n = min(sn, tn);
register int ans = 2 * n, dis = 0;
bool flag = 1;
for (register int i = 1; i <= n; ++i) {
if (!flag) {
dis = dis * 2;
if (s[i] == 0) ++dis;
if (t[i] == 1) ++dis;
}
if (s[i] != t[i] && flag) {
flag = 0;
if (s[i] == 1) swap(s, t);
}
if (dis > ans) break;
ans = min(ans, dis + !flag + 2 * (n - i));
}
cout << sum + ans << endl;
return 0;
}

Comments

Your browser is out-of-date!

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

×