Loading

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;
}




题目大意

给定一个由' . '组成的矩阵, 这个矩阵内部有个由'#'组成的小矩阵, 但是这个小矩阵有一个位置仍是' . ', 找出这个位置;

解题思路

签到题不多嗦了

神秘代码

#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;
}




题目大意

给定一个图, 有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;
}
posted @ 2023-06-21 23:59  mostimali  阅读(76)  评论(0)    收藏  举报