Skip to content

查看源代码:
NOIP-2024-code-review.md

---
title: 直面心魔——NOIP 2024 回顾(其二)
createTime: 2025/8/6
categories:
    - IT
tags:
    - OI
---

今日贤贤找到了我的 NOIP 的代码。

## 代码分析

这是我 T4 的 0 分代码:

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

const int maxn=5e5+100, maxlogn=20;
int st[maxn][maxlogn+10];
// lca(u,u)=u 可以使用st表
int fa[maxn][maxlogn+10];
int dep[maxn];
vector<int> G[maxn];

void dfs(int u, int from){
    fa[u][0] = from;
    dep[u] = dep[from] + 1;
    for (int v: G[u]){
        if (v == from){
            continue;
        }
        dfs(v, u);
    }
    
    for (int i=1; i<=maxlogn; i++){
        fa[u][i] = fa[fa[u][i-1]][i-1];
    }
}

inline int lca(int x, int y){
    if (dep[x] < dep[y]){
        swap(x, y);
    }
    
    for (int i=maxlogn; i>=0; i--){
        if (dep[fa[x][i]] >= dep[y]){
            x = fa[x][i];
        }
    }
    
    if (x == y){
        return x;
    }
    
    for (int i=maxlogn; i>=0; i--){
        if (fa[x][i] != fa[y][i]){
            x = fa[x][i];
            y = fa[y][i];
        }
    }
    
    return fa[x][0];
}

inline int floorlog(int x){
    int ans=0, pw=1;
    while (pw <= x){
        pw <<= 1;
        if (pw <= x){
            ans++;
        }
    }
    return ans;
}

inline int lcastar(int l, int r){
    int loglen=floorlog(r-l+1);
    return lca(st[l][loglen], st[r-(1<<loglen)+1][loglen]);
}

int main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    freopen("query.in", "r", stdin);
    freopen("query.out", "w", stdout);
    
    int n;
    cin >> n;
    for (int i=1; i<=n-1; i++){
        int u, v;
        cin >> u >> v;
        G[u].push_back(v);
        G[v].push_back(u);
    }
    
    dfs(1, 1);
    
    for (int i=1; i<=n; i++){
        st[i][0] = i;
    }
    for (int len=1; (1<<len)<=n; len++){
        for (int i=1; i<=n-(1<<len)+1; i++){
            st[i][len] = lca(st[i][len-1], st[i+(1<<(len-1))][len-1]);
        }
    }
    
    int q;
    cin >> q;
    
    while (q--){
        int l, r, k;
        cin >> l >> r >> k;
        int ans=0;
        for (int i=l; i+k-1<=r; i++){
            ans = max(ans, dep[lcastar(i, i+k-1)]);
        }
        cout << ans << '\n';
    }
    
    return 0;
}
```

找到哪里有问题了吗?

贤贤发现问题在此处:

```cpp
void dfs(int u, int from){
    fa[u][0] = from;
    dep[u] = dep[from] + 1;
    for (int v: G[u]){
        if (v == from){
            continue;
        }
        dfs(v, u);
    }
    
    for (int i=1; i<=maxlogn; i++){
        fa[u][i] = fa[fa[u][i-1]][i-1];
    }
}
```

`fa` 数组在 `dfs` 之前还未更新,导致下层递归无法获取正确的祖先信息。

交换这两段代码,可以在洛谷的数据上拿到 $\color{red}{32}$ 分。

什么概念?这 $\color{red}{32}$ 分已经可以让 P 某拿到省一,少努力一年了。

## tips

为什么能过样例一?——样例太水。  
为什么能过手造样例?——只有天知道。

为了避免玄学导致的错误:

- **打熟板子**
- **仔细捋清逻辑**(这是源头上的办法)
- **分步测试**
- **手造样例**(多几组,刁钻一些)
- **打印重要变量/数组**(记得删,不过交之前一般会过一遍 `fc`

## 附录:另外两道题的代码

### T1

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

const int maxn=1e5+100;
char s1[maxn], s2[maxn], t1[maxn], t2[maxn];

int belong1[maxn], belong2[maxn];

struct area {
    int cnt[4];
} sa1[maxn], sa2[maxn];
int sa1tot, sa2tot;

inline int min3(int a, int b, int c){
    return min(min(a, b), c);
}

int main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    freopen("edit.in", "r", stdin);
    freopen("edit.out", "w", stdout);
    
    int t;
    cin >> t;
    while (t--){
        memset(sa1, 0, sizeof sa1);
        memset(sa2, 0, sizeof sa2);
        sa1tot = sa2tot = 0;
        
        int n;
        cin >> n;
        cin >> s1+1 >> s2+1 >> t1+1 >> t2+1;
        
        for (int i=1; i<=n; i++){
            // new block?
            bool n1 = (t1[i]=='0' || t1[i]!=t1[i-1]);
            bool n2 = (t2[i]=='0' || t2[i]!=t2[i-1]);
//          printf("#%d n1=%d n2=%d\n", i, n1, n2);
            sa1tot += n1;
            sa2tot += n2;
            
            sa1[sa1tot].cnt[s1[i]-'0']++;
            sa2[sa2tot].cnt[s2[i]-'0']++;
            
            belong1[i] = sa1tot;
            belong2[i] = sa2tot;
        }
        
        int ans=0;
        for (int i=1; i<=n; i++){
            int bl1 = belong1[i], bl2=belong2[i];
            if (sa1[bl1].cnt[0] && sa2[bl2].cnt[0]){
//              printf("%d use %d # %d %d\n", i, 0, sa1[bl1].cnt[0], sa2[bl2].cnt[0]);
                sa1[bl1].cnt[0]--;
                sa2[bl2].cnt[0]--;
                ans++;
            } else if (sa1[bl1].cnt[1] && sa2[bl2].cnt[1]){
//                printf("%d use %d\n", i, 1);
                sa1[bl1].cnt[1]--;
                sa2[bl2].cnt[1]--;
                ans++;
            }
        }
        cout << ans << '\n';
    }
    
    return 0;
}
```

### T2

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

typedef long long ll;

const ll maxm=1e5+100, mod=1e9+7;
struct xianz {
    long long c, d;
    bool operator < (xianz &other){
        return c < other.c;
    }
    bool operator == (xianz &other){
        return c==other.c && d==other.d;
    }
} xz[maxm];

ll qpow(ll a, ll b){
    ll ans=1;
    while (b){
        if (b&1){
            ans *= a;
            ans %= mod;
        }
        a *= a;
        a %= mod;
        b >>= 1;
    }
    return ans % mod;
}

int main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    freopen("assign.in", "r", stdin);
    freopen("assign.out", "w", stdout);
    
    int t;
    cin >> t;
    while(t--){
//      memset(xz, 0, sizeof xz);
        long long n, m, v;
        cin >> n >> m >> v;
        for (int i=1; i<=m; i++){
            cin >> xz[i].c >> xz[i].d;
        }
        
        sort(xz+1, xz+m+1);
        m = unique(xz+1, xz+m+1) - (xz+1);
        
        ll ans=1;
        bool ansis0 = false;
        for (int i=2; i<=m; i++){
            if (xz[i].c == xz[i-1].c){
                ansis0 = true;
                break;
            }
            
            ll thans = qpow(v, 2*(xz[i].c-xz[i-1].c));
            ll noans = qpow(v, xz[i].c-xz[i-1].c-1);
            noans = noans * (v-1) % mod;
            ans *= (thans-noans+mod) % mod;
            ans %= mod;
//          printf("thans=%d, noans=%d\n", thans, noans);
        }
        
        if (m){
            ans *= qpow(v, 2*(xz[1].c-1));
            ans %= mod;
            ans *= qpow(v, 2*(n-xz[m].c));
            ans %= mod;
        } else {
            ans *= qpow(v, 2*(n-1));
            ans %= mod;
        }
        
        if (ansis0){
            cout << "0\n";
        } else {
            cout << ((ans+mod)%mod) << '\n';
        }
    }
    
    
    return 0;
}
```