AtCoder Beginner Contest 305
B - ABCDEFG
题目大意
给出A~G七个字母, 以及每个字母之间的权值, 输入两个字母, 输出两个字母之间的权重总和;
解题思路
前缀和签到题不多嗦了;
神秘代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
typedef pair<int,int> PII;
const int N = 10;
int n, m, k;
int d[] = { 0,3,1,4,1,5,9 };
int s[N];
signed main() {
for (int i = 1; i <= 6; i++) s[i] = s[i - 1] + d[i];
char a, b;
cin >> a >> b;
n = min(a - 'A', b - 'A');
m = max(a - 'A', b - 'A');
cout << s[m] - s[n];
return 0;
}
C - Snuke the Cookie Picker
题目大意
给定一个由' . '组成的矩阵, 这个矩阵内部有个由'#'组成的小矩阵, 但是这个小矩阵有一个位置仍是' . ', 找出这个位置;
解题思路
签到题不多嗦了
神秘代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
typedef pair<int,int> PII;
const int N = 510;
int n, m, k;
char g[N][N];
signed main() {
cin >> n >> m;
int l=N, r=0, u=N, d=0;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
cin >> g[i][j];
if (g[i][j] == '#') {
l = min(l, i);
r = max(r, i);
u = min(u, j);
d = max(d, j);
}
}
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
if (g[i][j] == '.') {
if (i >= l && i <= r && j >= u && j <= d) {
cout << i << ' ' << j;
return 0;
}
}
}
}
return 0;
}
D - Sleep Log
题目大意
小莫展示了他一天的作息时间, 给出了n个时间点, 第1个时间点为0, 第2i个时间点和第(2i+1)个时间点之间是小莫的睡眠时间, 其余时间为清醒时间, 给出m组询问, 每组询问是输入两个时间点, 问这个时间段内小莫的睡眠时间;
解题思路
这个题看着简单, 实际做起来其实还是有许多需要思考的点; 因为时间最多到1e9级别, 而n只有1e5级别, 所以我们可以对时间段进行处理; 对于n个时间点就有(n-1)个时间段, 我们对每个时间段进行编号, 睡眠时间段的值就是时间差, 而清醒时间段为0, 然后求时间段的前缀和; 此外我们可以让两个时间点中较大的那个代表整个时间段 (这个可以用map进行映射), 从而判断询问给出的时间点位于哪个时间段内; 然后在询问中, 对于两个时间点, 我们可以先用二分找到第一个大于等于它的时间点, 这样就可以找到包围询问时间段的两个时间段, 用前缀和得到大致答案后, 再对首尾的两个时间段进行具体的减补;
神秘代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
typedef pair<int, int> PII;
const int N = 1e6 + 10;
int n, m, k,z;
vector<int>v;
map<int, int> mp;
int g[N];
bool st[N];
signed main() {
cin >> n;
int maxn = 0;
cin >> z;
for (int i = 1; i < n; i++) {
int x;
cin >> x;
if (i % 2 == 0) {
g[i] = x - z;
st[i] = true;
}
else st[i] = false;
z = x;
v.push_back(x);
mp[x] = i;
}
for (int i = 1; i < n; i++) g[i] += g[i - 1];
cin >> m;
for (int i = 1; i <= m; i++) {
int res = 0;
int a, b;
cin >> a >> b;
auto l = lower_bound(v.begin(), v.end(), a) - v.begin();
auto r = lower_bound(v.begin(), v.end(), b) - v.begin();
int l1 = mp[v[l]];
int r1 = mp[v[r]];
res += g[r1] - g[l1];
if (st[l1]) res += v[l] - a;
if (st[r1]) res -= v[r] - b;
cout << res << endl;
}
return 0;
}
E - Art Gallery on Graph
题目大意
给定一个图, 有n个点和m条边, 每条边的权值为1; 然后又给出k个保安, 每个保安都位于不同的点上, 我们称这些点为监视点, 每个保安都有一个视野范围h, 凡是与监视点距离小于等于h的点都会被监视, 问都有哪些点被监视了(包括监视点), 升序输出;
解题思路
因为n, m, k, 都是1e5级别的, 所以不能用bfs, 所以我想着只能从边入手, 但是一直没有思路; 然后看了看佬的题解, 发现了一个炒鸡牛逼的做法; 我们先找出所有视野范围h中的最大值max, 我们可以另外创建一个点x, 让x连接所有监视点, 然后最牛逼的来了, 我们让x到监视点之间的权值为max-hi (hi为各自的视野范围); 这样我们从x点出发, 找到所有与x距离小于等于max的点就是被监视的点了; 于是这个题就变成了最短路问题;(真的太强了 Orz); 为了防止监视点通过x到达其他点, 我们可以让监视点到x的权值为无穷;
神秘代码
#include<bits/stdc++.h>
#define int long long
#define IOS ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define endl '\n'
using namespace std;
typedef pair<int, int> PII;
const int N = 2e5 + 10, mod = 998244353;
int n, m, k, idx;
vector<PII> v[N];
int f[N], d[N];
bool st[N];
void check(){
memset(d, 0x3f, sizeof d);
priority_queue<PII, vector<PII>, greater<PII>> heap;
heap.push({0, 0});
d[0] = 0;
while(heap.size()){
PII t = heap.top();
heap.pop();
int id = t.second;
if(st[id]) continue;
st[id] = true;
for(int i = 0; i < v[id].size(); i++){
int j = v[id][i].first, dis = v[id][i].second;
if(d[j] > d[id] + dis){
d[j] = d[id] + dis;
heap.push({d[j], j});
}
}
}
for(int i = 1; i <= n; i ++){
if(d[i] <= N) idx++;
}
}
signed main() {
cin >> n >> m >> k;
for(int i = 1; i <= m; i++){
int a, b;
cin >> a >> b;
v[a].push_back({b, 1});
v[b].push_back({a, 1});
}
for(int i = 1; i <= k; i++){
int a, b;
cin >> a >> b;
v[0].push_back({a, N - b});
}
check();
cout << idx << endl;
for(int i = 1; i <= n; i++){
if(d[i] <= N) cout << i << ' ';
}
return 0;
}
F - Dungeon Explore
难度: ⭐⭐⭐
题目大意
交互题; 现在有一个节点数为n的无向图, 小莫初始位于节点1; 开局输入节点数n和边数m; 然后接着给出与节点1相连的所有节点; 随后需要小莫输出其中的一个节点, 然后题目给出与该节点相连的所有节点; 需要小莫在2*n次输出内达到节点n;
解题思路
比较暴力的一道交互题; 我们可以暴力遍历所有点, 注意遍历的时候要打好标记, 不能重复走; 如果节点i的所有相邻节点都被打上标记了, 那么回溯的时候我们也要先输出i的前一个节点; 因为每条边最多走一次, 等价于每个点最多被输出两次, 不会超出限制; 可以用栈来保存当前的路径, 方便回溯的时候输出;
神秘代码
#include<bits/stdc++.h>
#define int long long
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
//#define endl '\n'
using namespace std;
const int N = 1e3 + 10, mod = 998244353;
typedef pair<int, int> PII;
int n, m;
bool st[N];
int f[N][N];
stack<int> s;
void dfs(int u) {
if (u == n) exit(0);
st[u] = true;
int num;
cin >> num;
for (int i = 1; i <= num; i++) {
cin >> f[u][i];
}
for (int i = 1; i <= num; i++) {
if (!st[f[u][i]]) {
s.push(u);
cout << f[u][i] << endl;
dfs(f[u][i]);
s.pop();
}
}
int t= s.top();
s.pop();
cout << t << endl;
dfs(t);
}
signed main() {
cin >> n >> m;
dfs(1);
return 0;
}

浙公网安备 33010602011771号