西南民族大学 春季 2023 训练赛 6

L1-1 今天我要赢

#include <bits/stdc++.h>

using namespace std;

int main() {
    cout << "I'm gonna win! Today!\n";
    cout << "2022-04-23\n";
    return 0;
}

L1-2 种钻石

#include <bits/stdc++.h>

using namespace std;

int main() {
    int a , b;
    cin >> a >> b;
    cout << a  / b;
    return 0;
}

L1-3 谁能进图书馆

注意要做到不重不漏

#include <bits/stdc++.h>

using namespace std;

int main() {
    int a , b , c , d;
    cin >> a >> b >> c >> d;
    if( c < a && d < a ){
        cout << c<<"-N " << d<<"-N\n";
        cout << "zhang da zai lai ba\n";
    }else if( c >= a && d >= a ){
        cout << c<<"-Y " << d << "-Y\n";
        cout << "huan ying ru guan\n";
    }else if( min(c,d) < a && max(c,d) >= b ){
        cout << c<<"-Y " << d << "-Y\n";
        if( c > d ) cout << "qing 1 zhao gu hao 2\n";
        else cout << "qing 2 zhao gu hao 1\n";
    }else{
        if( c > a ) cout << c << "-Y " << d << "-N\n" << "1: huan ying ru guan\n";
        else cout << c << "-N " << d << "-Y\n"<< "2: huan ying ru guan\n";
    }
}

L1-4 拯救外星人

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

int main() {
    ll a , b , c = 1;
    cin >> a >> b;
    for( int i = 2 ; i <= a+b ; i ++ )
         c *= i;
    cout << c;
}

L1-5 试试手气

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

int main() {
    vector<set<int>> st(6);
    for( int i = 0 ; i < 6 ; i ++ )
        for( int j = 1 ; j <= 6 ; j ++ )
            st[i].insert(j);
    for( int i = 0 , x ; i < 6 ; i ++ ){
        cin >> x;
        st[i].erase(x);
    }
    int n;
    cin >> n;
    for( n-= 1 ; n ; n -- ){
        for( int i = 0 ; i < 6 ; i ++ )
            st[i].erase( *st[i].rbegin() );
    }
    for( int i = 0 ; i < 6 ; i ++ )
        cout << *st[i].rbegin() << " \n"[i==5];
}

L1-6 斯德哥尔摩火车上的题

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

int main() {
    string a , b ,  c = "" , d = "";
    cin >> a >> b;
    for( int i = 1 ; i < a.size() ; i ++ ){
        if( a[i] % 2 == a[i-1]%2 )
            c += max( a[i] , a[i-1] );
    }
    for( int i = 1 ; i < b.size() ; i ++ ){
        if( b[i] % 2 == b[i-1] % 2 )
            d += max( b[i] , b[i-1] );
    }
    if( c == d ) cout << c << "\n";
    else cout << c << "\n" << d <<"\n";
}

L1-7 机工士姆斯塔迪奥

#include <bits/stdc++.h>

using namespace std;

#define int long long
typedef long long ll;

int32_t main() {
    set<int> r , c;
    int n , m , q;
    cin >> n >> m >> q;
    for( int x , y ; q ; q -- ){
        cin >> x >> y;
        if( x == 1 ) r.insert(y);
        else c.insert(y);
    }
    int res = 0;
    for( int i = 1 ; i <= n ; i ++ ){
        if( c.count(i) ) continue;
        for( int j = 1 ; j <= m ; j ++ ){
            if( r.count(j) ) continue;
            res ++;
        }
    }
    cout << res;
}

L1-8 静静的推荐

#include <bits/stdc++.h>

using namespace std;

int read() {
    int x = 0, f = 1, ch = getchar();
    while ((ch < '0' || ch > '9') && ch != '-') ch = getchar();
    if (ch == '-') f = -1, ch = getchar();
    while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
    return x * f;
}

int32_t main() {
    int n = read() , k = read() , s = read() , res = 0;
    vector<int> a(300);
    for( int x , y ; n ; n -- ){
        x = read() , y = read();
        if( x < 175 ) continue;
        if( y >= s ) res ++;
        else a[x] ++;
    }
    for( int i = 175 ; i <= 290 ; i ++ ) res += min( a[i] , k );
    cout << res ;
}

L2-1 插松枝

其实就是模拟题,多多读读题就好

#include <bits/stdc++.h>

using namespace std;

int read() {
    int x = 0, f = 1, ch = getchar();
    while ((ch < '0' || ch > '9') && ch != '-') ch = getchar();
    if (ch == '-') f = -1, ch = getchar();
    while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
    return x * f;
}

int32_t main() {
    int n = read(), m = read(), k = read();
    vector<int> pusher(n), box;
    vector<vector<int>> ans;
    for (auto &i: pusher) i = read();
    reverse(pusher.begin(), pusher.end());
    while (!pusher.empty() || !box.empty()) {
        vector<int> cur;
        if (!box.empty()) cur.push_back(box.back()), box.pop_back();
        else cur.push_back(pusher.back()), pusher.pop_back();
        while (cur.size() < k) {
            if (!box.empty() && box.back() <= cur.back())
                cur.push_back(box.back()), box.pop_back();
            else {
                while (!pusher.empty() && pusher.back() > cur.back() && box.size() < m)
                    box.push_back(pusher.back()), pusher.pop_back();
                if (!pusher.empty() && pusher.back() <= cur.back())
                    cur.push_back(pusher.back()), pusher.pop_back();
                else break;
            }
        }
        ans.push_back(cur);
    }
    for (const auto &it: ans) {
        cout << it.front();
        for (int i = 1; i < it.size(); i++)
            cout << " " << it[i];
        cout << "\n";
    }
    return 0;
}

L2-2 老板的作息表

把时间都转换成秒数,然后把区间都排个序,然后加上起止时间,逐个判断是否连贯即可

#include <bits/stdc++.h>

using namespace std;

int read() {
    int x = 0, ch = getchar();
    while (ch < '0' || ch > '9') ch = getchar();
    while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
    return x ;
}

int32_t main() {
    int n = read();
    vector<pair<int, int>> a;
    a.emplace_back(0, 0), a.emplace_back(24 * 60 * 60 - 1, 24 * 60 * 60 - 1);
    for (int l, r, h, m, s; n; n--) {
        h = read(), m = read(), s = read();
        l = (h * 60 + m) * 60 + s;
        h = read(), m = read(), s = read();
        r = (h * 60 + m) * 60 + s;
        a.emplace_back(l, r);
    }
    sort( a.begin(), a.end());
    for( int i = 1 , l , r , h , m , s; i < a.size() ; i ++ ){
        if( a[i].first == a[i-1].second ) continue;
        l = a[i-1].second , r = a[i].first;
        s = l % 60 , l /= 60;
        m = l % 60 , l /= 60;
        h = l;
        printf("%02d:%02d:%02d - " , h , m , s );
        s = r % 60 , r /= 60;
        m = r % 60 , r /= 60;
        h = r;
        printf("%02d:%02d:%02d\n" , h , m , s );
    }
    return 0;
}

L2-3 龙龙送外卖

我们考虑如果需要访问的点的条件有两种,第一种是本身要访问这个点,第二种是这个点子树中有点需要被访问。

可以考虑用带权并查集去维护一下当前的需要访问的树的大小。如果要求回到起点的话,树上的每一条边访问两边。现在要求不回去,所以最后一个点走到最深的点,然后直接结束。答案就是\(2(n-1)-maxdep\)\(n\)是当前树的大小,\(maxdep\)是最大深度。

对于每一个新加入的点,递归的加到当前的树上即可,加的时候顺便维护一下最大深度就好。

#include <bits/stdc++.h>

using namespace std;

int read() {
    int x = 0, f = 1, ch = getchar();
    while ((ch < '0' || ch > '9') && ch != '-') ch = getchar();
    if (ch == '-') f = -1, ch = getchar();
    while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
    return x * f;
}

vector<int> fa;
vector<int> g, dep;
int n, m, sta, maxDep;

int getfa(int x) {
    if (fa[x] < 0) return x;
    return fa[x] = getfa(fa[x]);
}

void dfs(int x) {
    if (getfa(x) == sta) return;
    dfs(g[x]);

    dep[x] = dep[g[x]] + 1, maxDep = max(maxDep, dep[x]);
    fa[sta] += fa[x], fa[x] = sta;
    return;
}

int32_t main() {
    n = read(), m = read(), sta = -1;
    g = vector<int>(n + 1);
    dep = vector<int>(n + 1, 0);
    for (int i = 1; i <= n; i++) {
        g[i] = read();
        if (g[i] == -1) sta = i;
    }
    fa = vector<int>(n + 1, -1);
    for (int u; m ; m--) {
        u = read();
        if (getfa(u) != sta) dfs(u);
        cout << -2 * (fa[sta] + 1) - maxDep << "\n";
    }
    return 0;
}

L2-4 大众情人

跑一个暴力的 Floyd,然后再暴力统计答案。

#include <bits/stdc++.h>

using namespace std;

int read() {
    int x = 0, f = 1, ch = getchar();
    while ((ch < '0' || ch > '9') && ch != '-') ch = getchar();
    if (ch == '-') f = -1, ch = getchar();
    while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
    return x * f;
}


int32_t main() {
    int n = read();
    vector<string> sex(n + 1);
    vector<int> F, M;
    vector<vector<int>> f(n + 1, vector<int>(n + 1, INT_MAX));
    for (int i = 1, m; i <= n; i++) {
        cin >> sex[i], m = read();
        for (int v, w; m; m--)
            v = read(), w = read(), f[i][v] = w;
    }
    for (int k = 1; k <= n; k++)
        for (int i = 1; i <= n; i++) {
            if (i == k || f[i][k] == INT_MAX) continue;
            for (int j = 1; j <= n; j++) {
                if (i == j || k == j || f[k][j] == INT_MAX) continue;
                f[i][j] = min(f[i][j], f[i][k] + f[k][j]);
            }
        }
    for (int i = 1; i <= n; i++) {
        if (sex[i] == "F") F.push_back(i);
        else M.push_back(i);
    }
    vector<int> Fval, Mval;
    for (int i = 1, val; i <= n; i++) {
        val = -1;
        if (sex[i] == "F") {
            for (auto j: M) val = max(val, f[j][i]);
            if (Fval.empty()) Fval.resize(2), Fval[0] = val, Fval[1] = i;
            else if (Fval[0] == val) Fval.push_back(i);
            else if (Fval[0] > val) Fval.resize(2), Fval[0] = val, Fval[1] = i;
        } else {
            for (auto j: F) val = max(val, f[j][i]);
            if (Mval.empty()) Mval.resize(2), Mval[0] = val, Mval[1] = i;
            else if (Mval[0] == val) Mval.push_back(i);
            else if (Mval[0] > val) Mval.resize(2), Mval[0] = val, Mval[1] = i;
        }
    }
    for( int i = 1 ; i < Fval.size() ; i ++ ) printf("%d%c" , Fval[i] , " \n"[i==Fval.size()-1] );
    for( int i = 1 ; i < Mval.size() ; i ++ ) printf("%d%c" , Mval[i] , " \n"[i==Mval.size()-1] );

    return 0;
}

L3-1 千手观音

首先根据题目的条件把每一个单词当成一个点,根据题目的描述建有向图出来。然后跑拓扑序,注意这里的拓扑序使用优先队列来保证顺序无法确定时按照字典序排列。最后为了简化操作,我把单词全部哈希了一下。

#include <bits/stdc++.h>

using namespace std;

int read() {
    int x = 0, f = 1, ch = getchar();
    while ((ch < '0' || ch > '9') && ch != '-') ch = getchar();
    if (ch == '-') f = -1, ch = getchar();
    while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
    return x * f;
}


int32_t main() {
    ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
    int n;
    cin >> n;
    vector<vector<string>> g(n);
    unordered_map<string, unordered_set<string>> p;
    unordered_map<string, int> deg;
    for (auto &it: g) {
        string s, t;
        cin >> s, t = "";
        for (const auto &i: s) {
            if (i == '.') it.push_back(t), deg[t], t = "";
            else t += i;
        }
        it.push_back(t), deg[t];
    }

    for (int i = 0, j; i < n; i++) {
        j = i + 1;
        if (g[i].size() != g[j].size()) continue;
        for (int k = 0; k < g[i].size(); k++) {
            if (g[i][k] == g[j][k]) continue;
            if (p[g[i][k]].insert(g[j][k]).second) deg[g[j][k]]++;
            break;
        }
    }
    vector<string> res;
    priority_queue<string, vector<string>, greater<string>> q;
    for (auto [k, v]: deg)
        if (v == 0) q.push(k);
    while (!q.empty()) {
        auto u = q.top();
        q.pop();
        res.push_back(u);
        for (auto v: p[u]) {
            deg[v]--;
            if (deg[v] == 0) q.push(v);
        }
    }
    for (int i = 0; i < res.size(); i++)
        cout << res[i] << ".\n"[i == res.size() - 1];
    return 0;
}

L3-2 关于深度优先搜索和逆序对的题应该不会很难吧这件事

首先如果每个点有\(v_i\)个子节点,这dfs序的总数为\(\sum (v_{i}!)\),记作\(cnt\)

如果\(a<b\),并且\(b\)\(a\)的祖先节点,在所有的 dfs序中都会有这个逆序对,贡献是\(cnt\),这里的统计可以用树状数组实现

如果\(a<b\),并且\(a\)\(b\)没有祖先关系,根据 dfs序的性质,在\(\frac{cnt}{2}\)个序中\(a,b\)会形成逆序对,贡献\(\frac {cnt}2\)。我们其实没有必要统计对于当前的\(a\)有多少个\(b\)满足大与\(a\),而是有多少个\(b\)\(a\)没有祖先关系,其实就是所有的点去掉\(a\)的祖先节点们再去掉\(a\)的子树中的节点,这个可以用dfs统计。但注意,这样会导致重复统计,在统计\(a\)的时候会计入\(b\),在统计\(b\)的时候又会计入\(a\),为此我们可以把贡献修改为\(\frac{cnt}4\)即可

思路来源

#include<bits/stdc++.h>

using namespace std;

#define int long long

int read() {
    int x = 0, f = 1, ch = getchar();
    while ((ch < '0' || ch > '9') && ch != '-') ch = getchar();
    if (ch == '-') f = -1, ch = getchar();
    while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
    return x * f;
}

const int mod = 1e9 + 7;

int n, sta, cnt = 1, s1, s2;
vector<int> b, fact, sz;
vector<vector<int>> e;

int power(int x, int y) {
    int ans = 1;
    while (y) {
        if (y & 1) ans = ans * x % mod;
        y >>= 1, x = x * x % mod;
    }
    return ans;
}

int inv(int x) {
    return power(x, mod - 2);
}

#define lowbit(x) ( x & -x )


void add(int x, int y) {
    for (int i = x; i <= n; i += lowbit(i)) b[i] += y;
    return;
}

int get(int x) {
    int ans = 0;
    for (int i = x; i; i -= lowbit(i)) ans += b[i];
    return ans;
}

void dfs(int u, int fa, int dep) {
    add(u, 1);
    if (fa == -1) cnt = cnt * fact[e[u].size()] % mod;
    else cnt = cnt * fact[e[u].size()-1] % mod;
    s1 = (s1 + get(n) - get(u)) % mod;

    for (auto v: e[u]) {
        if (v == fa) continue;
        dfs(v, u, dep + 1);
        sz[u] += sz[v];
    }

    s2 = (s2 + n - dep - sz[u]) % mod;

    add(u, -1);
    return;
}

int32_t main() {
    n = read(), sta = read();
    b = vector<int>(n + 1), fact = vector<int>(n + 1);
    sz = vector<int>(n + 1, 1), sz[0] = 0;
    fact[0] = 1;
    for (int i = 1; i <= n; i++) fact[i] = fact[i - 1] * i % mod;
    e = vector<vector<int>>(n + 1);
    for (int i = 1, u, v; i < n; i++)
        u = read(), v = read(), e[u].push_back(v), e[v].push_back(u);

    dfs(sta, -1, 0);

    cout << (s1 * cnt % mod + s2 * cnt % mod * inv(4) % mod) % mod;
    return 0;
}
posted @ 2023-04-12 21:31  PHarr  阅读(31)  评论(0编辑  收藏  举报