2025-12-28noip模拟测验总结

拿了 \(100 + 65 + 100 + 100 = 365\),rank 2。

膜拜 george AK %%%。

T1 冒泡排序

见过结论()

题意简述

\(T(T \leq 10^5)\) 次询问,每次给定 \(n(n \leq 10^7)\),求长为 \(n\) 的随机排列期望最少 swap 多少次可以有序。

题解

结论:\(ans_i = i - \sum\limits_{j = 1}^i \frac{1}{j}\)

参考代码:

#include<bits/stdc++.h>
#define int long long
using namespace std;
inline int read(){
    int x = 0, f = 1;
    char ch = getchar();
    while(!isdigit(ch)){
        if(ch == '-') f = -1;
        ch = getchar();
    }
    while(isdigit(ch)){
        x = (x << 1) + (x << 3) + (ch ^ 48);
        ch = getchar();
    }
    return x * f;
}
inline void write(int x){
    if(x < 0) putchar('-'), x = -x;
    if(x > 9) write(x / 10);
    putchar(x % 10 + '0');
    return;
}
inline int fp(int a, int b, int p){
    int res = 1;
    while(b){
        if(b & 1) res = res * a % p;
        a = a * a % p;
        b >>= 1;
    }
    return res;
}
const int Mod = 998244353;
int inv[10000005], ans[10000005];
//ans[i] = i - (1/1 + 1/2 + ... + 1/i)
inline void init(){
    inv[1] = 1;
    for(int i = 2; i <= 1e7; i++){
        inv[i] = Mod - Mod / i * inv[Mod % i] % Mod;
        ans[i] = ((ans[i - 1] + 1 - inv[i]) % Mod + Mod) % Mod;
    }
    return;
}
signed main(){
    init();
    int T = read();
    while(T--) write((ans[read()] % Mod + Mod) % Mod), putchar('\n');
    return 0;
}

T2 情报中心

以为能过就没上 bitset(\kk

题意简述

给定一张 \(n\) 个点,\(m\) 条边的 \(1\) 权图,共有 \(q\) 次询问,每次给定 \(k\)\((u, d)\),表示距 \(u\) 不超过 \(d\) 的点都是好的,求出每次询问好的点的个数。

数据范围:\(1 \leq n,q \leq 1000\)\(1 \leq m \leq 10^5\)\(1 \leq \sum k \leq 2 \times 10^6\)

题解

\(v_{u, d}\) 表示距离 \(u\) 不超过 \(d\) 的点的集合。

显然,可以通过 \(n\) 次 bfs 求出所有 \(v\)(这是 \(1\) 权图)。

此时,使用 bitset 按位或运算即可。

时间复杂度会除个 \(w\),然后就过了。

参考代码:

#pragma GCC optimize("Ofast")
#pragma GCC optimize("unroll-loops")
#pragma GCC optimize("inline")
#pragma GCC optimize("-ffast-math")
#pragma GCC optimize("-falign-loops")
#pragma GCC optimize("-funroll-loops")
#pragma GCC optimize("-fstrict-aliasing")
#include<bits/stdc++.h>
// #define int long long
using namespace std;
inline int read(){
    int x = 0, f = 1;
    char ch = getchar();
    while(!isdigit(ch)){
        if(ch == '-') f = -1;
        ch = getchar();
    }
    while(isdigit(ch)){
        x = (x << 1) + (x << 3) + (ch ^ 48);
        ch = getchar();
    }
    return x * f;
}
inline void write(int x){
    if(x < 0) putchar('-'), x = -x;
    if(x > 9) write(x / 10);
    putchar(x % 10 + '0');
    return;
}
bitset<1005> v[1005][1005], res;
vector<int> e[1005];
int n, m;
queue<pair<int, int> > q;
int vis[1005];
inline void bfs(int s){
    while(!q.empty()) q.pop();
    memset(vis, 0, sizeof(vis));
    q.push({s, 0}), vis[s] = true;
    while(!q.empty()){
        int u = q.front().first, d = q.front().second;
        q.pop();
        v[s][d][u] = 1;
        for(auto v : e[u]){
            if(!vis[v]){
                vis[v] = true;
                q.push({v, d + 1});
            }
        }
    }
    return;
}
signed main(){
    n = read(), m = read(); int qq = read();
    for(int i = 1; i <= m; i++){
        int u = read(), v = read();
        e[u].push_back(v), e[v].push_back(u);
    }
    for(int i = 1; i <= n; i++) bfs(i);
    for(int u = 1; u <= n; u++){
        for(int d = 1; d <= n; d++){
            v[u][d] |= v[u][d - 1];
        }
    }
    while(qq--){
        int k = read();
        res.reset();
        for(int i = 1; i <= k; i++){
            int u = read(), d = read();
            res |= v[u][d];
        }
        write(res.count()), putchar('\n');
    }
    return 0;
}

T3 百鸽笼

怎么还有板子题(

题意简述

维护一个序列,支持如下操作:

  1. 把序列最左边的那个数扬了

  2. 在序列最左边插入一个数

  3. 查询区间第 \(k\)

保证 \(n, q \leq 10^5, |V| \leq 10^9\),256 MB。

题解

主席树板子啊,第二个操作和建主席树的操作一样。

注意卡卡空间。

参考代码:

#pragma GCC optimize("Ofast")
#pragma GCC optimize("unroll-loops")
#pragma GCC optimize("inline")
#pragma GCC optimize("-ffast-math")
#pragma GCC optimize("-falign-loops")
#pragma GCC optimize("-funroll-loops")
#pragma GCC optimize("-fstrict-aliasing")
#include<bits/stdc++.h>
// #define int long long
using namespace std;
bool ST;
inline int read(){
    int x = 0, f = 1;
    char ch = getchar();
    while(!isdigit(ch)){
        if(ch == '-') f = -1;
        ch = getchar();
    }
    while(isdigit(ch)){
        x = (x << 1) + (x << 3) + (ch ^ 48);
        ch = getchar();
    }
    return x * f;
}
inline void write(int x){
    if(x < 0) putchar('-'), x = -x;
    if(x > 9) write(x / 10);
    putchar(x % 10 + '0');
    return;
}
int n, q, a[200005], b[400005], rt[400005], tot;
struct Ask{
    int op;
    int l, r, k;
}ask[400005];
struct SegT{
    int ls, rs;
    int sum;
}t[20000005];
inline void build(int &p, int l, int r){
    if(!p) p = ++tot;
    if(l == r) return;
    int mid = (l + r) >> 1;
    build(t[p].ls, l, mid), build(t[p].rs, mid + 1, r);
    return;
}
inline void modify(int &p, int yuanp, int x, int PL, int PR){
    if(x < PL || x > PR) return;
    p = ++tot;
    t[p] = t[yuanp], t[p].sum++;
    if(x <= PL && PR <= x) return;
    int mid = (PL + PR) >> 1;
    modify(t[p].ls, t[yuanp].ls, x, PL, mid), modify(t[p].rs, t[yuanp].rs, x, mid + 1, PR);
    return;
}
inline int query(int pl, int pr, int k, int PL, int PR){
    if(PL == PR) return PL;
    int cntl = t[t[pr].ls].sum - t[t[pl].ls].sum;
    int mid = (PL + PR) >> 1;
    if(cntl >= k) return query(t[pl].ls, t[pr].ls, k, PL, mid);
    return query(t[pl].rs, t[pr].rs, k - cntl, mid + 1, PR);
}
bool ED;
signed main(){
    // freopen("input.in", "r", stdin);
    // freopen("output.out", "w", stdout);
    n = read(), q = read();
    int btot = 0;
    for(int i = 1; i <= n; i++) a[i] = b[++btot] = read();
    for(int i = 1; i <= q; i++){
        ask[i].op = read();
        if(ask[i].op == 1){
            //
        }else if(ask[i].op == 2){
            ask[i].k = read();
            b[++btot] = ask[i].k;
        }else{
            ask[i].l = read(), ask[i].r = read(), ask[i].k = read();
        }
    }
    sort(b + 1, b + 1 + btot);
    int V = unique(b + 1, b + 1 + btot) - b - 1;
    for(int i = 1; i <= n; i++){
        a[i] = lower_bound(b + 1, b + 1 + V, a[i]) - b;
    }
    for(int i = 1; i <= q; i++){
        if(ask[i].op == 2){
            ask[i].k = lower_bound(b + 1, b + 1 + V, ask[i].k) - b;
        }
    }
    // for(int i = 1; i <= n; i++) cout << a[i] << ' ';
    // cout << '\n' << V << '\n';
    build(rt[0], 1, V);
    for(int i = 1; i <= n; i++) modify(rt[i], rt[i - 1], a[n - i + 1], 1, V);
    int nowr = n;
    for(int i = 1; i <= q; i++){
        if(ask[i].op == 1){
            nowr--;
        }else if(ask[i].op == 2){
            modify(rt[nowr + 1], rt[nowr], ask[i].k, 1, V);
            nowr++;
        }else{
            int r = nowr - ask[i].l + 1, l = nowr - ask[i].r + 1;
            // cout << l << ' ' << r << '\n';
            write(b[query(rt[l - 1], rt[r], ask[i].k, 1, V)]), putchar('\n');
        }
    }
    // cerr << 1.0 * (&ED - &ST) / 1024.0 / 1024.0 << " MB" << '\n';
    return 0;
}

T4 方块

感觉不难,为啥只有两个人过这题(

题意简述

赛后被翻出原题了:https://www.luogu.com.cn/problem/UVA1030

题解

考虑贪心,每次从近到远删方块即可。

时间复杂度大概是 \(\mathcal{O}(Tn^4)\) 的(?)

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

int n;
string view[10][20];
char cube[20][20][20];

// 从左到右,从上到下,从前到后
inline tuple<int, int, int> calc(int s, int r, int c, int t){
    if(s == 1) return {c, r, t};
    else if(s == 2)return {t, r, n - c + 1};
    else if(s == 3) return {n - c + 1, r, n - t + 1};
    else if(s == 4) return {n - t + 1, r, c};
    else if(s == 5) return {c, t, n - r + 1};
    else if(s == 6)return {c, n - t + 1, r};
    return {-1, -1, -1};
}

inline void Solve(){
    for(int i = 1; i <= n; i++){
        for(int s = 1; s <= 6; s++){
            cin >> view[s][i];
            view[s][i] = ' ' + view[s][i];
        }
    }
    for(int x = 1; x <= n; x++){
        for(int y = 1; y <= n; y++){
            for(int z = 1; z <= n; z++){
                cube[x][y][z] = '#';
            }
        }
    }
    for(int s = 1; s <= 6; s++){
        for(int x = 1; x <= n; x++){
            for(int y = 1; y <= n; y++){
                if(view[s][x][y] == '.'){
                    for(int t = 1; t <= n; t++){
                        auto [xx, yy, zz] = calc(s, x, y, t);
                        cube[xx][yy][zz] = '.';
                    }
                }
            }
        }
    }

    bool changed = true;
    while(changed){
        changed = false;
        for(int s = 1; s <= 6; s++){
            for(int x = 1; x <= n; x++){
                for(int y = 1; y <= n; y++){
                    char want = view[s][x][y];
                    if(want == '.') continue;
                    // 近 -> 远
                    for(int t = 1; t <= n; t++){
                        auto [xx, yy, zz] = calc(s, x, y, t);
                        if(cube[xx][yy][zz] == '.') continue;
                        if(cube[xx][yy][zz] == '#'){
                            cube[xx][yy][zz] = want;
                            changed = true;
                            break;
                        }
                        if(cube[xx][yy][zz] == want) break;
                        cube[xx][yy][zz] = '.', changed = true;
                    }
                }
            }
        }
    }

    int ans = 0;
    for(int x = 1; x <= n; x++){
        for(int y = 1; y <= n; y++){
            for(int z = 1; z <= n; z++){
                if(cube[x][y][z] != '.'){
                    ans++;
                }
            }
        }
    }
    cout << "Maximum weight: " << ans << " gram(s)" << '\n';
    return;
}
signed main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr), cout.tie(nullptr);
    
    while(cin >> n && n) Solve();
    return 0;
}
/*
3
.R. YYR .Y. RYY .Y. .R.
GRB YGR BYG RBY GYB GRB
.R. YRR .Y. RRY .R. .Y.
2
ZZ ZZ ZZ ZZ ZZ ZZ
ZZ ZZ ZZ ZZ ZZ ZZ
0
*/
posted @ 2025-12-28 14:12  zhang_kevin  阅读(14)  评论(0)    收藏  举报