现场4题,第二天补题时发现hard版本的直接用当时写的easy版代码就能过,结果是当时因为网太卡就没试,感觉亏爆。0.o

A. Chips Moving

 

签到,奇数或偶数内部是等价的,只有在奇偶之间转化时才会+1,因此只要看奇数和偶数哪个个数少。

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
#include<iostream>
#include<stdio.h>
#include<cstring>
#include<string>
#include<vector>
#include<algorithm>
#include<set>
#include<cmath>
using namespace std;
#define ll long long
const int maxn = 1e6 + 5;
int n;
int c1, c2;
int main() {
cin.sync_with_stdio(false);
cin >> n;
for (int i = 0; i < n; i++) {
int a;
cin >> a;
if (a & 1)c1++;
else c2++;
}
cout << min(c1, c2);
return 0;
}

 

B. Bad Prices

 

对于一个数,如果它之后有比它小的数,它就是bad girl,bad price.

所以从后往前找,始终记录后面的数中最小值,如果当前数大于后面数最小值,则当前数为bad,若当前数小于最小值,则更新最小值。

直接变量记录就好了,当时还写了优先队列,完全没必要。

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<iostream>
#include<stdio.h>
#include<cstring>
#include<string>
#include<vector>
#include<algorithm>
#include<set>
#include<cmath>
#include<queue>
using namespace std;
#define ll long long
const int maxn = 1e6 + 5;
int n, t;
int a[maxn];
int main() {
cin.sync_with_stdio(false);
cin >> t;
while (t--) {
int ans = 0;
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> a[i];
}
priority_queue<int,vector<int>,greater<int> >q;
for (int i = n; i >= 0; i--) {
if (q.empty()) {
q.push(a[i]);
continue;
}
if (a[i] > q.top())ans++;
else q.push(a[i]);
}
cout << ans << endl;
}
return 0;
}

 

C. Book Reading

 

一个数的倍数的末尾数字是有规律的,最多以10为周期,因此提前记一下周期,之后再看能出现几个周期,多出来的暴力模拟一下。

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
#include<iostream>
#include<stdio.h>
#include<cstring>
#include<string>
#include<vector>
#include<algorithm>
#include<set>
#include<cmath>
#include<queue>
#include<map>
using namespace std;
#define ll long long
const int maxn = 1e6 + 5;
ll n, m;
int t;
map<int, int>mp;
map<int, int>M;
int main() {
mp[1] = 10; mp[2] = 5; mp[3] = 10; mp[4] = 5; mp[5] = 2;
mp[6] = 5; mp[7] = 10; mp[8] = 5; mp[9] = 10; mp[0] = 1;
for (int i = 0; i < 10; i++) {
int res = 0;
for (int j = 1; j <= mp[i]; j++) {
res += (i*j) % 10;
}
M[i] = res;
}
cin.sync_with_stdio(false);
cin >> t;
while (t--) {
ll ans = 0;
cin >> n >> m;
int t = m % 10;
ll cnt = n / m;
ans += M[t] * (cnt / mp[t]);
int rest = cnt % mp[t];
for (int i = 1; i <= rest; i++) {
ans += (i*t) % 10;
}
cout << ans << endl;
}
return 0;
}

 

D1. Equalizing by Division (easy version)

 

给定一个数列,对每个数能进行整除2的操作任意次,求最小操作几次使数列中有k个相同的数。

对于一个数,由它能得到它经过几次整除2后的数,因此对每一次整除2后得到的数,记录操作的次数,当能得到某一个数的途径大于等于k时,看操作次数是否为最小值。

由于对数列排过序,因此从左到右得到相同数需要的操作次数一定也是由小到大的。贪心是成立的。

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
#include<iostream>
#include<stdio.h>
#include<cstring>
#include<string>
#include<vector>
#include<algorithm>
#include<set>
#include<cmath>
#include<queue>
#include<map>
using namespace std;
#define ll long long
const int maxn = 2e5 + 5;
const int INF = 0x3f3f3f3f;
int n, k;
vector<int>vc[maxn];
int a[maxn];
int main() {
cin.sync_with_stdio(false);
cin >> n >> k;
for (int i = 1; i <= n; i++)
cin >> a[i];
sort(a + 1, a + n + 1);
for (int i = 1; i <= n; i++) {
int b = a[i];
int cnt = 0;
while (b) {
if (vc[b].size() >= k) {
b >>= 1;
continue;
}
vc[b].push_back(cnt);
b >>= 1;
cnt++;
}
if (vc[0].size() >= k)continue;
vc[0].push_back(cnt);
}
int ans = INF;
for (int i = 0; i < maxn; i++) {
if (vc[i].size() < k)continue;
int res = 0;
for (auto v : vc[i])res += v;
ans = min(ans, res);
}
cout << ans;
return 0;
}

 

D2. Equalizing by Division (hard version)

 

和上一题一样。

 

G. Path Queries

 

似乎是某一年的icpc网络赛类似题,但当时是队友写的。

一数对(u,v),要求u,v的路径上所有边的边权最大值不能超过q。求数对个数。

带权并查集

我们知道若(a,b),(b,c)满足条件,则(a,c)也满足,那么就是从一堆数任意挑出两个数组成数对,即求组合数。

先对询问排序,以减少不必要的回头次数。

用并查集,根节点的rk表示该并查集有几个点。两个集合合并时把rk相加。

合并集合的同时更新答案。注意计算组合数时精度。

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
#include<iostream>
#include<stdio.h>
#include<cstring>
#include<string>
#include<vector>
#include<algorithm>
#include<set>
#include<cmath>
#include<queue>
#include<map>
using namespace std;
#define ll long long
typedef pair<int, int> pii;
const int maxn = 2e5 + 5;
int n, m;
vector<pair<int,pii>>E;
vector<pii>qus;
ll tmp;
ll ans[maxn];
int par[maxn];
int rk[maxn];
ll cal(int x) {
return 1ll*x * (x - 1) / 2;
}
void init(int n) {
for (int i = 1; i <= n; i++) {
par[i] = i;
rk[i] = 1;
}
}
int find(int x) {
if (par[x] == x)return x;
return par[x] = find(par[x]);
}
void unit(int x, int y) {
x = find(x);
y = find(y);
if (x == y)return;
if (rk[x] < rk[y]) {
par[x] = y;
tmp = tmp - cal(rk[x]) - cal(rk[y]) + cal(rk[x] + rk[y]);
rk[y] = rk[y] + rk[x];
}
else {
par[y] = x;
tmp = tmp - cal(rk[x]) - cal(rk[y]) + cal(rk[x] + rk[y]);
rk[x] = rk[x] + rk[y];
}
}
int main() {
cin.sync_with_stdio(false);
cin >> n >> m;
init(n);
for (int i = 0; i < n - 1; i++) {
int u, v, w;
cin >> u >> v >> w;
E.push_back(make_pair(w, pii(u, v)));
}
sort(E.begin(), E.end());
for (int i = 0; i < m; i++) {
int k;
cin >> k;
qus.push_back(pii(k, i));
}
sort(qus.begin(), qus.end());
int cnt = 0;
for (int i = 0; i < m; i++) {
int k = qus[i].first;
while (cnt < n - 1 && E[cnt].first <= k) {
unit(E[cnt].second.first, E[cnt].second.second);
cnt++;
}
ans[qus[i].second] = tmp;
}
for (int i = 0; i < m; i++) {
cout << ans[i] << ' ';
}
return 0;
}