2025寒假专场11

· · 题解

最强程序员

入门,模拟

我们可以用建树的思想找入度即可, ab强就让b的入度加一, 最后如果只有一个人没有入度, 说明他就是最强的; 如果有多个说明无法确定;

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;

int n,m;
bool st[N];
int main(){
    cin >> n >> m;
    for(int i = 1; i <= m; i++){
        int a,b;
        cin >> a >> b;
        st[b] = true;
    }
    int ans = 0;
    for(int i = 1; i <= n; i++){
        if(!st[i]){
            if(ans == 0) ans = i;
            else {
                cout << -1;
                return 0;
            }
        }
    }
    cout << ans;
    return 0;
}

轮盘赌

入门,模拟

#include<bits/stdc++.h>

using namespace std;
const int N = 100 + 10;

int n, m, idx;
int c[N];
set<int> s[N];
vector<int> v;
bool cmp(int a, int b) {
    if (c[a] == c[b]) return a < b;
    return c[a] < c[b];
}
int main() {
    cin >> n;
    for (int i = 1; i <= n; i++) {
        cin >> c[i];
        for (int j = 1; j <= c[i]; j++) {
            int x;
            cin >> x;
            s[i].insert(x);
        }
    }
    cin >> idx;
    for (int i = 1; i <= n; i++) {
        if (s[i].count(idx)) v.push_back(i);
    }
    if (v.empty()) {
        cout << 0 << endl;
        return 0;
    }
    sort(v.begin(), v.end(), cmp);
    int minn = c[*v.begin()];
    for (int i = 0; i < v.size(); i++) {
        if (c[v[i]] == minn) m++;
        else break;
    }
    cout << m << endl;
    for (int i = 0; i < m; i++) {
        cout << v[i] << " ";
    }
    return 0;
}

最短路

可以从 1,N_1 + N_2 出发,分别进行 BFS ,找该图中以其为起点,最短路最长的点。之后把这两个点连起来,就是题目需要的答案。

#include<bits/stdc++.h>
using namespace std; 
void solve(){
    int n1, n2, m; 
    cin >> n1 >> n2 >> m;
    vector<int> e[n1 + n2 + 2], vis(n1 + n2 + 2, 0), d(n1 + n2 + 2, 0);
    for(int i = 1; i <= m; i++){
        int u, v;
        cin >> u >> v;
        e[u].push_back(v);
        e[v].push_back(u);
    }

    int m1 = 0, m2 = 0;
    queue<int> q; 
    q.push(1); d[1] = 0; vis[1] = 1;
    while(q.size()){
        int cur = q.front();  q.pop();
        for(auto y : e[cur]){
            if( !vis[y] ){
                q.push(y);
                vis[y] = 1;
                d[y] = d[cur] + 1;
                m1 = max(m1, d[y]);
            }
        }
    }

    q.push(n1 + n2); d[n1 + n2] = 0; vis[n1 + n2] = 1;
    while(q.size()){
        int cur = q.front();  q.pop();
        for(auto y : e[cur]){
            if(!vis[y]){
                q.push(y);
                vis[y] = 1;
                d[y] = d[cur] + 1;
                m2 = max(m2, d[y]);
            }
        }
    }
    cout << m1 + m2 + 1 << '\n';
}
int main(){
    solve();
    return 0;
}

家庭保险

首先记录每个人买到的保险最多可以保护几代人。之后从族谱的根节点开始更新,记录当前这个人买的或者继承的族谱最多可以再保护几代人。

#include<bits/stdc++.h>
using namespace std;
const int N = 3e5 + 10;
const int M = 2 * N;
int fa[N];
vector<int>g[M];
int n, m, col[N]; 
void dfs(int x, int f){
    col[x] = max(col[x], col[f] - 1);
    for(auto y: g[x]){
        if(y == f) continue;
        dfs(y, x);
    }
}
int main(){
    scanf("%d%d", &n, &m);
    for(int i = 2; i <= n; i++){
        int x; scanf("%d", &x);
        fa[i] = x;
        g[i].push_back(x);
        g[x].push_back(i);
    }
    for(int i = 1; i <= m; i++){
        int x, y;
        scanf("%d%d", &x, &y);
        col[x] = max(col[x], y + 1);
    }
    dfs(1, 0);
    int ans = 0;
    for(int i = 1; i <= n; i++)
        if(col[i])
            ans++;
    printf("%d\n", ans);
    return 0;
}

无孔方块

二维前缀和+二分。

枚举左上角的位置,二分满足条件的正方形的边长,时间复杂度为n*mlogn

#include<bits/stdc++.h>
using namespace std;
const int N = 3000 + 10;
int sum[N][N], a[N][N];
int n, m, k;
bool check(int x, int y, int len){
    int nx = x + len - 1;
    int ny = y + len - 1;
    int res = sum[nx][ny] - sum[nx][y - 1] - sum[x - 1][ny] + sum[x - 1][y - 1];
    return res == 0;
}

int main(){
    scanf("%d%d%d", &n, &m, &k);
    for(int i = 1; i <= k; i++){
        int x, y;
        scanf("%d%d", &x, &y);
        a[x][y] = 1;
    }

    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= m; j++)
            sum[i][j] = sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1] + a[i][j];

    long long ans = 0;
    for(int i = 1; i <= n; i++){
        for(int j = 1; j <= m; j++){
            int l = 0, r = min(n - i + 1, m - j + 1);
            int len;
            while(l <= r){
                int mid = (l + r) / 2;
                if(check(i, j, mid)){
                    len = mid;
                    l = mid + 1;
                }
                else
                    r = mid - 1;
            }
            ans += 1ll * len;
        }
    }
    printf("%lld\n", ans);
    return 0;
}