C - Boss
题意:给出一个有向无环图,每条边x->y表示x是y的直属上司。两种操作,一种T x y表示将x和y的岗位互换,一种P x表示查询x的所有上司(直接或非直接领导)中的最小年龄
题解:用两个数组id1 id2。id1[i]表示在原关系图中i位置上的人现在的编号,id2[i]表示编号为i的人现在的位置。通过这两个数组可以在交换位置的时候O(1)更换位置并更新数组,具体细节看代码吧。
#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米,给定一个长度,和每种巴士的不同颜色数,求所有不同排列情况的数量的后六位
题解:递推部分比较简单, d p i dp_i dpi表示长度为 i ∗ 5 i*5 i∗5时共有多少种不同的放置情况,则可以分最后放置的是大巴还是小巴,并进行转移。
转移式是这样的 d p i = d p i − 1 ∗ k + d p i − 2 ∗ l dp_i = dp_{i-1}*k+dp_{i-2}*l dpi=dpi−1∗k+dpi−2∗l其中k是小巴的颜色数量,l是大巴的颜色数量
但这道题数据范围是1e15,递推也做不了,故需要使用矩阵快速幂来快速求解。可以推出 [ f i − 2 , f i − 1 ] ∗ [ 0 l 1 k ] = [ f i − 1 , f i ] [f_{i-2},f_{i-1}]* \left[ \begin{matrix} 0 & l \\ 1 & k \end{matrix} \right] =[f_{i-1},f_i] [fi−2,fi−1]∗[01lk]=[fi−1,fi]则 [ f n − 1 , f n ] = [ f i − 2 , f i − 1 ] ∗ [ 0 l 1 k ] n − 1 [f_{n-1},f_{n}] = [f_{i-2},f_{i-1}]*\left[ \begin{matrix} 0 & l \\ 1 & k \end{matrix} \right]^{n-1} [fn−1,fn]=[fi−2,fi−1]∗[01lk]n−1后半部分可以使用矩阵快速幂求并取模,则可以求出最终答案
#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;
}