2013-2014-Brazil-Subregional-Programming-Contest

  1. 1. C - Boss
  2. 2. H - Buses

C - Boss

题意:给出一个有向无环图,每条边x->y表示x是y的直属上司。两种操作,一种T x y表示将x和y的岗位互换,一种P x表示查询x的所有上司(直接或非直接领导)中的最小年龄

题解:用两个数组id1 id2。id1[i]表示在原关系图中i位置上的人现在的编号,id2[i]表示编号为i的人现在的位置。通过这两个数组可以在交换位置的时候O(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
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
#include <bits/stdc++.h>

using namespace std;
#define fast \
ios_base::sync_with_stdio(false); \
cin.tie(NULL);
const int N = 1e3 + 10;
const int M = 1e6 + 10;
const int INF = 0x3f3f3f3f;
const long long LINF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9 + 7;
const double eps = 1e-3;
set<int> up[N];
int age[N];
int vis[N];
int id1[N], id2[N];
int bfs(int x) {
memset(vis, 0, sizeof vis);
queue<int> q;
q.push(x);
int res = INF;
while (!q.empty()) {
int u = q.front();
q.pop();
for (auto it : up[u]) {
if (vis[it]) continue;
q.push(it);
vis[it] = 1;
//通过位置找到现在在这个位置上的编号,并更新最小年龄
res = min(res, age[id1[it]]);
}
}
return res;
}
int main() {
int n, m, I;
cin >> n >> m >> I;
for (int i = 1; i <= n; i++) {
id1[i] = i;
id2[i] = i;
}
for (int i = 1; i <= n; i++) scanf("%d", &age[i]);
for (int i = 1; i <= m; i++) {
int x, y;
scanf("%d%d", &x, &y);
up[y].insert(x);
}
for (int i = 1; i <= I; i++) {
char o[2];
scanf("%s", o);
if (o[0] == 'T') {
int x, y;
scanf("%d%d", &x, &y);
// 交换编号x和y所在位置的编号,并交换编号x和y的所在位置
swap(id1[id2[x]], id1[id2[y]]);
swap(id2[x], id2[y]);
} else {
int x;
scanf("%d", &x);
// 找到编号x的现在位置
x = id2[x];
int w = bfs(x);
if (w == INF)
puts("*");
else
printf("%d\n", w);
}
}
return 0;
}

H - Buses

题意:小巴长5米,大巴长10米,给定一个长度,和每种巴士的不同颜色数,求所有不同排列情况的数量的后六位

题解:递推部分比较简单,$dp_i$表示长度为$i*5$时共有多少种不同的放置情况,则可以分最后放置的是大巴还是小巴,并进行转移。

转移式是这样的$dp_i = dp_{i-1}k+dp_{i-2}l$其中k是小巴的颜色数量,l是大巴的颜色数量

但这道题数据范围是1e15,递推也做不了,故需要使用矩阵快速幂来快速求解。可以推出$[f_{i-2},f_{i-1}]
\left[
\begin{matrix}
0 & l \\
1 & k
\end{matrix}
\right] =[f_{i-1},f_i]$则$[f_{n-1},f_{n}] = [f_{i-2},f_{i-1}]
\left[
\begin{matrix}
0 & l \\
1 & k
\end{matrix}
\right]^{n-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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include <bits/stdc++.h>

using namespace std;
#define fast \
ios_base::sync_with_stdio(false); \
cin.tie(NULL);
const int N = 1e2 + 10;
const int M = 1e6 + 10;
const int INF = 0x3f3f3f3f;
const long long LINF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e6;
const double eps = 1e-3;
long long a[2][2], res[2][2] = {1,0,0,1};
void cheng(long long a[][2], long long b[][2], long long c[][2]){
long long d[2][2] = {0};
for(int i = 0;i<2;i++){
for(int j = 0;j<2;j++){
for(int k = 0;k<2;k++){
d[i][j] += (a[i][k] * b[k][j])%mod;
d[i][j] %= mod;
}
}
}
memcpy(c,d,sizeof d);
}
void fastpow(long long k){
while(k){
if(k&1) cheng(res,a,res);
cheng(a,a,a);
k = k>>1;
}
}
int main(){
long long n,k,l;
cin>>n>>k>>l;
k %= mod;
l %= mod;
n /= 5;
a[0][1] = l,a[1][0] = 1, a[1][1] = k;
fastpow(n - 1);
printf("%06d\n", (res[0][1] % mod + k * res[1][1] % mod) % mod);
return 0;
}