Skip to content

2026夏组队训练赛第九场

C. Bay

从外往里搜是很多棵树,回溯的时候统计块大小,枚举边的时候去两侧答案较小的一个(取儿子而不是父亲)

cpp
#include <bits/stdc++.h>

using namespace std;
const int N = 310;
int f[N][N], row[N][N], col[N][N];
int n, m;

void dfs(int x, int y, int px, int py) {
    if (f[x][y] != f[0][0]) return;
    f[x][y] = 1;
    if (x + 1 < n && !row[x + 1][y] && (x + 1 != px || y != py)) dfs(x + 1, y, x, y), f[x][y] += f[x + 1][y];
    if (x - 1 >= 1 && !row[x][y] && (x - 1 != px || y != py)) dfs(x - 1, y, x, y), f[x][y] += f[x - 1][y];
    if (y + 1 < n && !col[x][y + 1] && (x != px || y + 1 != py)) dfs(x, y + 1, x, y), f[x][y] += f[x][y + 1];
    if (y - 1 >= 1 && !col[x][y] && (x != px || y - 1 != py)) dfs(x, y - 1, x, y), f[x][y] += f[x][y - 1];
}

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);
    cin >> n >> m;
    for (int i = 1; i <= n * n - 1; ++i) {
        int a, b;
        cin >> a >> b;
        pair<int, int> aa = {(a - 1) / n + 1, (a - 1) % n + 1}, bb = {(b - 1) / n + 1, (b - 1) % n + 1};
        if (aa.first == bb.first) row[aa.first][aa.second] = 1;
        else col[aa.first][aa.second] = 1;
    }
    memset(f, 0x3f3f3f3f, sizeof(f));
    for (int i = 1; i < n; ++i) {
        if (!row[1][i]) dfs(1, i, 0, 0);
        if (!row[n][i]) dfs(n - 1, i, 0, 0);
        if (!col[i][1]) dfs(i, 1, 0, 0);
        if (!col[i][n]) dfs(i, n - 1, 0, 0);
    }
    int t = 0, x = 0, y = 0;
    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= n; ++j) {
            // if (j != n && !row[i][j]) cout << min(f[i][j], f[i - 1][j]) << '\n';
            if (j != n && !row[i][j] && min(f[i][j], f[i - 1][j]) == m) {
                t++;
                if (!x) x = (i - 1) * n + j, y = (i - 1) * n + j + 1;
            }
            if (i != n && !col[i][j] && min(f[i][j], f[i][j - 1]) == m) {
                t++;
                if (!x) x = (i - 1) * n + j, y = i * n + j;
            }
        }
    }
    cout << t << '\n' << x << ' ' << y << '\n';
    return 0;
}

D. Bookshelf

cpp
#pragma GCC optimize("O2")
#include <bits/stdc++.h>
#include <complex>
using namespace std;
#define int long long
#define i64 int64_t
#define db long double
#define pii pair<int, int>
#define tiii tuple<int, int, int>
#define ull unsigned long long
#define vi vector<int>

using i128 = __int128;
#define vpii vector<pii>
#define vvpii vector<vector<pii>>
#define vvi vector<vi>
#define pqpii priority_queue<pii, vector<pii>, greater<pii>>
#define pqi priority_queue<int, vi, greater<int>>
#define f first
#define s second
#define all(x) (x).begin(), (x).end()
#define pb push_back
#define eb emplace_back
#define sz(x) (x).size()
#define mp make_pair
#define bit bitset<N>
#define endl '\n'
void pr(vector<int> a) {
    for (auto i : a)
        cout << i << ' ';
    cout << '\n';
}
const int mod = 998244353;
const int INF = 1e18;
const int N = 129;
int p[N], p2[N];

void init() {}

void solve() {
    int n, l;
    cin >> n >> l;
    vpii a(n);
    int sum = 0;
    for (int i = 0; i < n; i++) {
        cin >> a[i].f;
    }
    for (int i = 0; i < n; i++) {
        cin >> a[i].s;
        sum += a[i].s;
    }
    int ps, h;
    cin >> ps >> h;
    int sum1 = 0;
    for (int i = 0; i < n; i++) {
        if (a[i].s > l - sum)
            sum1 += a[i].s;
    }
    if (a[ps - 1].s <= l - sum) {
        int q = 0;
        if (q <= h && l - sum1 + q >= h + a[ps - 1].s) {
            cout << "YES" << endl;
            return;
        }
        for (int i = 0; i < n; i++) {
            if (a[i].s > l - sum)
                q += a[i].s;
            if (q <= h && l - sum1 + q >= h + a[ps - 1].s) {
                cout << "YES" << endl;
                return;
            }
        }
        // cout << 111 << endl;
        cout << "NO" << endl;
    } else {
        int q = 0;
        for (int i = 0; i < ps - 1; i     ++) {
            if (a[i].s > l - sum)
                q += a[i].s;
        }
        if (q <= h && l - sum1 + q >= h)
            cout << "YES" << endl;
        else
            cout << "NO" << endl;
    }
}

signed main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    init();

    int t = 1;
    // cin >> t;
    while (t--)
        solve();

    return 0;
}

E. Clean Arrangement

显然子树的下标是连续的,把连向父亲的边拆成从自己到边界,和从边界到父亲两段。在对于非根的节点需要统计自己内部的和从自己到边界的,根节点只需要统计自己内部的。考虑贡献,对于非根节点贡献值为子树数量 + 子树大小构成的数组和 0,1,1,2,2,3,3... 内积最小值求和,对于根节点贡献值为子树数量 + 子树大小构成的数组和 0,0,1,1,2,2,3,3... 内积最小值求和,显然一个顺序和一个逆序的内积是最小的,直接按照子树大小排个序算即可。

cpp
#include <bits/stdc++.h>
#define int long long

using namespace std;
const int N = 5010;

int f[N], cnt[N];
vector<int> adj[N];

bool cmp(const int &a, const int &b) {
    return cnt[a] < cnt[b];
}

void dfs(int x, int fa) {
    cnt[x] = 1;
    vector<int> t;
    for (int &y : adj[x]) {
        if (y == fa) continue;
        dfs(y, x);
        f[x] += f[y];
        cnt[x] += cnt[y];
        t.emplace_back(y);
    }
    sort(t.begin(), t.end(), cmp);
    f[x] += t.size();

    // cout << x << '\n';
    // for (int i = 0; i < t.size(); ++i) cout << cnt[t[i]] << ' ';
    // cout << '\n';
    for (int i = 0; i < t.size(); ++i) {
        f[x] += (i + (x != 1)) / 2 * cnt[t[t.size() - i - 1]];
    }
}


signed main() {
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);
    int n;
    cin >> n;
    for (int i = 1; i < n; ++i) {
        int x, y;
        cin >> x >> y;
        adj[x].emplace_back(y);
        adj[y].emplace_back(x);
    }
    dfs(1, 0);
    // for (int i = 1; i <= n; ++i) cout << f[i] << ' ';
    // cout << '\n';
    cout << f[1] << '\n';
    return 0;
}

G. Extraterrestrial Creatures

cpp
#include <bits/stdc++.h>
using namespace std;
using ll = long long;

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);

    ll n, x;
    cin >> n >> x;

    vector<ll> a(n + 1), b(n + 1);
    for (int i = 1; i <= n; i ++) cin >> a[i];
    for (int i = 1; i <= n; i ++) cin >> b[i];

    ll l = 0, r = 1e18;

    auto calc = [&](ll t) -> bool {
        __int128_t use = 0;
        for (int i = 1; i <= n; i ++) {
            if (b[i] == 0) {
                use += 1e12;
                continue;
            }
            ll need = (t - a[i]);
            ll k = max(0ll,(need + b[i] - 1) / b[i]);
            use += k;
        }
        return use <= x;
    };

    while (l < r) {
        ll mid = (l + r + 1) >> 1;
        if (calc(mid)) l = mid;
        else r = mid - 1;
    }

    for (int i = 1; i <= n; i ++) {
        ll need = (l - a[i]);
        ll k = max(0ll,(need + b[i] - 1) / b[i]);
        x -= k;
        a[i] += k * b[i];
    }

    priority_queue<pair<ll, ll>, vector<pair<ll, ll>>, greater<pair<ll, ll>>> pq;

    for (int i = 1; i <= n; i ++) {
        pq.push({a[i], i});
    }

    while (x --) {
        auto [val, pos] = pq.top();
        pq.pop();
        a[pos] += b[pos];
        pq.push({a[pos], pos});
    }

    for (int i = 1; i <= n; i ++) cout << a[i] << ' ';
}

I. Magic Door

cpp
#pragma GCC optimize(2)
#include <bits/stdc++.h>
using namespace std;

int a[81][81];
//-3 ac_bomb
//-2 blank
//-1 wall
//0 bomb

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);

    int n, m;
    cin >> n >> m;

    for (int i = 1; i <= n; i ++) {
        for (int j = 1; j <= m; j ++) {
            cin >> a[i][j];
        }
    }

    int x1, x2, y1, y2;
    cin >> x1 >> y1 >> x2 >> y2;

    swap(a[x1][y1], a[x2][y2]);
    int changes = 1, bomb_active = 0;

    queue<pair<int, int>> bombs, dels;

    auto print = [&]() {
        cout << "-----------------\n";
        for (int i = 1; i <= n; i ++) {
            for (int j = 1; j <= m; j ++) {
                cout << a[i][j] << ' ';
            }
            cout << '\n';
        }
    };

    auto fall = [&]() -> void {
        //cout << "fall\n";
        //print();
        for (int col = 1; col <= m; col ++) {
            int pos = n;
            for (int row = n; row >= 1; row --) {
                if (a[row][col] == -2) continue;
                if (pos != row) changes = 1;
                if (a[row][col] == 0 && pos != row) {
                    a[pos --][col] = -3;
                    bomb_active = 1;
                }
                else a[pos --][col] = a[row][col];

            }
            for (; pos >= 1; pos --) a[pos][col] = -2;
        }
    };

    auto del = [&]() -> void {
        changes = 0;
        int na[81][81];
        for (int i = 1; i <= 80; i ++) for (int j = 1; j <= 80; j ++) na[i][j] = a[i][j];

        for (int row = 1; row <= n; row ++) {
            for (int col = 1; col <= m; col ++) {
                if (a[row][col] <= 0) continue;
                int r = col;
                while (r + 1 <= m && a[row][r + 1] == a[row][col]) r ++;
                if (r - col + 1 >= 3) for (int i = col; i <= r; i ++) na[row][i] = -2;
                col = r;
            }
        }
        for (int col = 1; col <= m; col ++) {
            for (int row = 1; row <= n; row ++) {
                if (a[row][col] <= 0) continue;
                int r = row;
                while (r + 1 <= n && a[r + 1][col] == a[row][col]) r ++;
                if (r - row + 1 >= 3) for (int i = row; i <= r; i ++) na[i][col] = -2;
                row = r;
            }
        }
        
        for (int i = 1; i <= 80; i ++) {
            for (int j = 1; j <= 80; j ++) {
                a[i][j] = na[i][j];
            }
        }
        fall();
    };

    auto bomb = [&]() -> void {
        bomb_active = 0;
        int na[81][81];
        for (int i = 1; i <= 80; i ++) for (int j = 1; j <= 80; j ++) na[i][j] = a[i][j];

        for (int row = 1; row <= n; row ++) {
            for (int col = 1; col <= m; col ++) {
                if (a[row][col] == -3) {
                    na[row][col] = -2;
                    for (int u = row - 1; u >= 1; u --) {
                        if (a[u][col] == -1) break;
                        else na[u][col] = -2;
                    }
                    for (int d = row + 1; d <= n; d ++) {
                        if (a[d][col] == -1) break;
                        else na[d][col] = -2;
                    }
                    for (int l = col - 1; l >= 1; l --) {
                        if (a[row][l] == -1) break;
                        else na[row][l] = -2;
                    }
                    for (int r = col + 1; r <= m; r ++) {
                        if (a[row][r] == -1) break;
                        else na[row][r] = -2;
                    }
                }
            }
        }

        for (int i = 1; i <= 80; i ++) {
            for (int j = 1; j <= 80; j ++) {
                a[i][j] = na[i][j];
            }
        }
        fall();
    };



    //print();
    while (changes || bomb_active) {
        while(changes) {
            del();
            //cout << "del\n";
            //print();
        }
        if (bomb_active) {
            bomb();
            //cout << "bomb\n";
            //print();
        }
    }

    int ans = 0;
    for (int i = 1; i <= n; i ++) {
        for (int j = 1; j <= m; j ++) {
            if (a[i][j] == -2) ans ++;
        }
    }
    cout << ans;
}

L. Segments

实际上 y 坐标没用,只需要右端点最小值和左端点最大值。

cpp
#include <bits/stdc++.h>

using namespace std;

typedef long long LL;

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);
    int n, q;
    LL mn = LLONG_MAX, mx = LLONG_MIN;
    cin >> n >> q;
    for (int i = 1; i <= n; ++i) {
        LL a, b, c;
        cin >> a >> b >> c;
        mn = min(mn, b), mx = max(mx, a);
    }
    while (q--) {
        LL x;
        cin >> x;
        cout << max(0LL, max(x - mn, mx - x)) << '\n';
    }
    return 0;
}

M. Triple Fairness

cpp
#include <bits/stdc++.h>
using namespace std;

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);

    int n;
    cin >> n;
    
    for (int i = 1; i <= n; i ++) cout << i << ' ';

    if (n % 3 == 0) {
        for (int i = 2; i <= n; i ++) cout << i << ' ';
        cout << 1 << ' ';

        for (int i = 3; i <= n; i ++) cout << i << ' ';
        cout << 1 << ' ';
        cout << 2;
    }
    else {
        for (int i = 1; i <= n; i ++) cout << i << ' ';
        for (int i = 1; i <= n; i ++) cout << i << ' ';
    }
}

其他没做的题

  • Adventurer Dabi
  • Badge Relay
  • CPEquivalence
  • Fair Problemset
  • Mex Culpa
  • Quadrants