14届
3 冶炼金属
小蓝有一个神奇的炉子用于将普通金属 O 冶炼成为一种特殊金属 X。这个炉子有一个称作转换率的属性 V,V 是一个正整数,这意味着消耗 V 个普通金属 O 恰好可以冶炼出一个特殊金属 X,当普通金属 O 的数目不足 V 时,无法继续冶炼。
现在给出了 N 条冶炼记录,每条记录中包含两个整数 A 和 B,这表示本次投入了 A 个普通金属 O,最终冶炼出了 B 个特殊金属 X。每条记录都是独立的,这意味着上一次没消耗完的普通金属 O 不会累加到下一次的冶炼当中。
根据这 N 条冶炼记录,请你推测出转换率 V 的最小值和最大值分别可能是多少,题目保证评测数据不存在无解的情况。
Solution
二分答案
#define int long long
void solve() {
int n;cin >> n;
vector<int>a(n + 1), b(n + 1);
for (int i = 1;i <= n;i++) {
cin >> a[i] >> b[i];
}
int l = 1, r = 1e10;
while (l < r) {
int mid = l + r >> 1;
bool ok = true;
for (int i = 1;i <= n;i++) {
if (a[i] / mid > b[i])ok = false;
}
if (ok)r = mid;
else l = mid + 1;
}
cout << l << " ";
l = 1, r = 1e10;
while (l < r) {
int mid = l + r >> 1;
bool ok = true;
for (int i = 1;i <= n;i++) {
if (a[i] / mid < b[i])ok = false;
}
if (!ok)r = mid;
else l = mid + 1;
}
cout << l - 1 << " ";
}
4 飞机降落
架飞机降落完毕时,另一架飞机可以立即在同一时刻开始降落,但是不能在前一架飞机完成降落前开始降落。
请你判断 N 架飞机是否可以全部安全降落。
Solution
DFS
void solve() {
int n;cin >> n;vector<int>t(n + 1), d(n + 1), l(n + 1), vis(n + 1);
for (int i = 1;i <= n;i++)cin >> t[i] >> d[i] >> l[i];
bool ok = false;
auto dfs = [&](auto self, int cnt, int last)->void {
if (cnt == n) {
ok = true;return;
}
for (int i = 1;i <= n;i++) {
if (!vis[i] && t[i] + d[i] >= last) {
vis[i] = 1;
self(self, cnt + 1, max(last, t[i]) + l[i]);
vis[i] = 0;
}
}
};
dfs(dfs, 0, 0);
if (ok)cout << "YES\n";
else cout << "NO\n";
}
5 接龙数列
对于一个长度为
所有长度为 1 的整数数列都是接龙数列。
现在给定一个长度为
Solution
DP
int f[10];
void solve() {
int n, m = 0;cin >> n;
for (int i = 1;i <= n;i++) {
string s;cin >> s;
int x = s[0] - '0', y = s[s.size() - 1] - '0';
f[y] = max(f[y], f[x] + 1);
m = max(m, f[y]);
}
cout << n - m << '\n';
}
6 岛屿个数
求给定的地图有多少个岛屿
Solution
BFS
只要一个岛屿中一个点在另一个岛屿中,则为它的子岛屿
先算出地图中所有的连通块,
每个岛屿只需要记录其中一个点即可。
遍历所有的岛屿,若能够到达地图的外围,则一定算一个岛屿,否则,就是其他岛屿的子岛屿,这时答案需要
注:为什么第二个 BFS 使用的是 8 个方位呢?
因为我们无法保证所有的连通块都是环,当 8 个方位移动时,可以排除是非环岛屿但是可能走不出该非环岛屿的情况,换句话说,使用 8 个方位,若走不出来一定能保证外圈岛屿是环
int dx[] = {0,0,1,-1};
int dy[] = {1,-1,0,0};
void solve() {
int n, m;cin >> n >> m;
vector<vector<char>> s(n + 1, vector<char>(m + 1));
vector<vector<int>> vis(n + 1, vector<int>(m + 1));
for (int i = 1;i <= n;i++) {
for (int j = 1;j <= m;j++) {
cin >> s[i][j];
}
}
int cnt = 0;
auto bfs = [&](int x, int y) {
queue<pair<int, int>>q;q.push({x,y});vis[x][y] = cnt;
while (q.size()) {
auto [x, y] = q.front();q.pop();
for (int i = 0;i < 4;i++) {
int a = x + dx[i], b = y + dy[i];
if (a<1 || b<1 || a>n || b>m) continue;
if (vis[a][b] || s[a][b] == '0')continue;
vis[a][b] = cnt;q.push({a,b});
}
}
};
vector<pair<int, int>> pcnt;
for (int i = 1;i <= n;i++) {
for (int j = 1;j <= m;j++) {
if (s[i][j] == '1' && !vis[i][j]) {
cnt++;bfs(i, j);pcnt.push_back({i,j});
}
}
}
int dx2[] = {0,0,1,-1,1,1,-1,-1};
int dy2[] = {1,-1,0,0,1,-1,1,-1};
vector<vector<int>> vis2(n + 1, vector<int>(m + 1));
auto bfs2 = [&](int x, int y) ->bool {
queue<pair<int, int>>q;q.push({x,y});
while (q.size()) {
auto [x, y] = q.front();q.pop();
for (int i = 0;i < 8;i++) {
int a = x + dx2[i], b = y + dy2[i];
if (a<1 || b<1 || a>n || b>m) {
return true;
}
if (vis[a][b] || vis2[a][b] || s[a][b] == '1')continue;
vis2[a][b] = 1;q.push({a,b});
}
}
return false;
};
for (auto [x, y] : pcnt) {
for (int i = 1;i <= n;i++) {
for (int j = 1;j <= m;j++) {
vis2[i][j] = 0;
}
}
if (!bfs2(x, y))cnt--;
}
cout << cnt << '\n';
}
7 子串简写
给定一个字符串
Solution
前缀和
#define int long long
void solve() {
int k;cin >> k;string s;cin >> s;s = ' ' + s;char a, b;cin >> a >> b;
int n = s.size() - 1;
vector<int> pre(n * 2);
for (int i = n;i >= 1;i--) {
pre[i] = pre[i + 1] + (s[i] == b);
}
int ans = 0;
for (int i = 1;i <= n;i++) {
if (s[i] == a) {
ans += pre[i + k - 1];
}
}
cout << ans << '\n';
}
8 整数删除
给定一个长度为
每次选择数列中最小的整数 (如果最小值不止一个,选择最靠前的),将其删除。并把与它相邻的整数加上被删除的数值。
输出
Solution
链表
没懂
#define int long long
void solve() {
int n, k;cin >> n >> k;
priority_queue <pair<int, int>, vector <pair<int, int>>, greater<pair<int, int>>> q;
vector<int> l(n + 10), r(n + 10), cnt(n + 10), a(n + 10);
for (int i = 1;i <= n;i++) {
int x;cin >> x;q.push({x,i});
l[i] = i - 1;r[i] = i + 1;
}
while(q.size() > n - k) {
auto [x, id] = q.top();q.pop();
if (cnt[id]) {
q.push({x + cnt[id],id});cnt[id] = 0;
} else {
cnt[l[id]] += x;
cnt[r[id]] += x;
l[r[id]] = l[id];
r[l[id]] = r[id];
}
}
while (q.size()) {
auto [x, id] = q.top();q.pop();
a[id] = x + cnt[id];
}
for (int i = 1;i <= n;i++) {
if (a[i])cout << a[i] << " ";
}
}
9 景区导游
某景区一共有
小明是这个景区的资深导游,他每天都要按固定顺序带客人游览其中飞个景点:
请你对任意一个
Solution
倍增/LCA
暴力
#define int long long
void solve() {
int n, k;cin >> n >> k;
vector<vector<pair<int, int>>> g(n + 1);
for (int i = 1;i < n;i++) {
int u, v, t;cin >> u >> v >> t;g[u].push_back({v,t});g[v].push_back({u,t});
}
vector<int> op(k + 5);
for (int i = 1;i <= k;i++) cin >> op[i];
vector<vector<int>> dis(n + 1, vector<int>(n + 1));
for (int i = 1;i <= n;i++) {
queue<int>q;vector<int> vis(n + 1);
q.push(i);vis[i] = 1;
while (q.size()) {
int u = q.front();q.pop();
for (auto [x, y] : g[u]) {
if (vis[x])continue;
vis[x] = 1;
dis[i][x] = dis[i][u] + y;
q.push(x);
}
}
}
int cnt = 0;
for (int j = 2;j <= k;j++) {
cnt += dis[op[j]][op[j - 1]];
}
for (int i = 1;i <= k;i++) {
cout << cnt - dis[op[i]][op[i + 1]] - dis[op[i]][op[i - 1]] + dis[op[i - 1]][op[i + 1]] << ' ';
}
}