2021NUAA暑期模拟赛部分题解

比赛链接:2021 nuaa 暑期模拟赛
比赛码:1234554321



D - 然叔的玩具熊

答案是单调的,考虑每个数能成为答案的最大区间长度,即这个数是区间最小值,所以找每个数前后第一个小于它的即可得到最长长度,短的长度可以通过后缀最大传递下来。
单调栈可以(O(n))

#include <cstdio>
#include <iostream>
#include <stack>
using namespace std;

int n, h[200010];
int len[200010];  // len[i]表示大小为i的分组中力量的最大值
struct node {  // num:数值  loc:能被作为答案的最大区间的最左端位置
    int num, loc;
};
stack<node> st;

int main() {
    scanf("%d", &n);
    for (int i = 1; i <= n; ++i) {
        scanf("%d", &h[i]);
    }
    h[++n] = 0;  // 在序列末尾加上0使其他数都出栈
    for (int i = 1; i <= n; ++i) {
        if (st.empty()) {
            st.push(node{h[i], i});
        } else if (!st.empty() && h[i] >= st.top().num) {
            st.push(node{h[i], i});
        } else {
            int nowloc = i;
            while (!st.empty() && st.top().num > h[i]) {
                int loc = st.top().loc, x = st.top().num;
                st.pop();
                nowloc = loc;            // 区间变大,最左端更新
                if (len[i - loc] < x) {  // 更新答案
                    len[i - loc] = x;
                }
            }
            st.push(node{h[i], nowloc});
        }
    }
    for (int i = n - 1; i >= 1; --i) {  // 从后往前更改答案使其单调递减
        if (len[i] < len[i + 1]) {
            len[i] = len[i + 1];
        }
    }
    for (int i = 1; i <= n - 1; ++i) {
        printf("%d ", len[i]);
    }
    return 0;
}

H - Good Array

签到题,分两种情况直接输出即可。

#include <iostream>
using namespace std;
int t, n, s;
int main() {
	s = 0;
	cin >> t;
	while (t--) {
		s = 0;
		int x;
		cin >> n;
		for (int i = 1; i <= n; ++i) {
			cin >> x;
			s += x;
		}
		if (s >= n) {
			cout << s - n << endl;
		} else {
			cout << 1 << endl;
		}
	}
	return 0;
}

I - 恶灵传说

首先通过广度优先搜索找出所有存在危险的城市,通过堆优化时间。
再通过最短路找到最小花费,安全城市花费为P,危险城市花费为Q,被占领城市花费为无穷大即不可走。

#include <iostream>
#include <queue>
using namespace std;

int n, m, k, s, p, q, x;
int vis[100010];  // 0 安全 1 危险 2 被占领 3 被占领
int cnt, head[100010];
long long dis[100010];
struct Edge {
    int len, v, next;
} edge[400010];
struct dj_node {
    int id;
    long long dis;
    bool operator<(const dj_node &obj) const { return dis > obj.dis; }
};
struct bfs_node {
    int id, dis;
    bool operator<(const bfs_node &obj) const { return dis < obj.dis; }
};
priority_queue<bfs_node> bfs_pq;

void addEdge(int u, int v, int w) {
    edge[++cnt].v = v;
    edge[cnt].len = w;
    edge[cnt].next = head[u];
    head[u] = cnt;
    // 无向图
    edge[++cnt].v = u;
    edge[cnt].len = w;
    edge[cnt].next = head[v];
    head[v] = cnt;
}

void find_danger() {  // 堆优化广搜
    while (!bfs_pq.empty()) {
        int id = bfs_pq.top().id, dis = bfs_pq.top().dis;
        bfs_pq.pop();
        if (vis[id] != 1 && vis[id] != 3) {
            for (int i = head[id]; i; i = edge[i].next) {
                if (edge[i].len <= dis) {
                    bfs_pq.push(bfs_node{edge[i].v, dis - edge[i].len});
                }
            }
            if (vis[id] == 0) {
                vis[id] = 1;
            } else if (vis[id] == 2) {
                vis[id] = 3;
            }
        }
    }
}

void dijkstra() {  // 最短路
    priority_queue<dj_node> dj_pq;
    for (int i = 1; i <= n; ++i) {
        dis[i] = 0x3f3f3f3f;
    }
    dis[1] = 0;
    dj_pq.push(dj_node{1, 0});
    while (!dj_pq.empty()) {
        int id = dj_pq.top().id;
        long long Dis = dj_pq.top().dis;
        dj_pq.pop();
        if (Dis > dis[id]) continue;
        for (int i = head[id]; i; i = edge[i].next) {
            if (vis[edge[i].v] == 3) {
                continue;
            } else if (vis[edge[i].v] == 1) {
                if (dis[edge[i].v] > Dis + q) {
                    dis[edge[i].v] = Dis + q;
                    dj_pq.push(dj_node{edge[i].v, dis[edge[i].v]});
                }
            } else if (vis[edge[i].v] == 0) {
                if (dis[edge[i].v] > Dis + p) {
                    dis[edge[i].v] = Dis + p;
                    dj_pq.push(dj_node{edge[i].v, dis[edge[i].v]});
                }
            }
        }
    }
}

int main() {
    cin >> n >> m >> k >> s >> p >> q;
    for (int i = 1; i <= k; ++i) {
        cin >> x;
        vis[x] = 2;
        bfs_pq.push(bfs_node{x, s});
    }
    int u, v, w;
    for (int i = 1; i <= m; ++i) {
        cin >> u >> v >> w;
        addEdge(u, v, w);
    }
    find_danger();
    dijkstra();
    if (vis[n] == 3) {
        cout << -1 << endl;
    } else if (vis[n] == 1) {
        cout << dis[n] - q << endl;
    } else {
        cout << dis[n] - p << endl;
    }
    return 0;
}

K - 数字矩阵

标记多少行多少列有(0)即可,如果(i)(j)列有(0),答案即为(i*m+j*n-i*j)

#include <iostream>
using namespace std;

int x[2010], y[2010], ii, jj, n, m;

int main() {
    cin >> n >> m;
    int num;
    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= m; ++j) {
            cin >> num;
            if (!num) {
                x[i] = 1;
                y[j] = 1;
            }
        }
    }
    for (int i = 1; i <= n; ++i) {
        ii += x[i];
    }
    for (int j = 1; j <= m; ++j) {
        jj += y[j];
    }
    cout << ii * m + jj * n - ii * jj << endl;
    return 0;
}
原文地址:https://www.cnblogs.com/IzumiSagiri/p/14998254.html