2013-2014-Brazil-Subregional-Programming-Contest 题解

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 i5时共有多少种不同的放置情况,则可以分最后放置的是大巴还是小巴,并进行转移。

转移式是这样的 d p i = d p i − 1 ∗ k + d p i − 2 ∗ l dp_i = dp_{i-1}*k+dp_{i-2}*l dpi=dpi1k+dpi2l其中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] [fi2,fi1][01lk]=[fi1,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} [fn1,fn]=[fi2,fi1][01lk]n1后半部分可以使用矩阵快速幂求并取模,则可以求出最终答案

#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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值