zoukankan      html  css  js  c++  java
  • AtCoder Beginner Contest 170 (D~F题,D筛法,E multiset使用,F Dijkstra算法改进)

    题目链接:Here

    ABC水题,

    D. Not Divisible

    看了题解才想到,可以用 Sieve of Eratosthenes,因为 (A_i) 最大才 (10^6)

    但有注意的点

    1
    1
    5
    2 2 2 3 3
    5
    2 2 2 4 4
    5
    1 1 1 1 2
    

    重复出现的数字

    简单的说:找出数列中不是其他数的倍数的数的个数(拗口)。用小数筛大数。

    const int N = 1e6 + 10;
    int a[N], cnt[N];
    bool st[N];
    int main() {
        cin.tie(nullptr)->sync_with_stdio(false);
        int n; cin >> n;
        for (int i = 1; i <= n; ++i) cin >> a[i], cnt[a[i]] += 1;
        for (int i = 1; i <= N; ++i) {
            if (cnt[i]) {
                if (cnt[i] > 1) st[i] = 1; // 对于重复出现的数据也要标记
                for (int j = i + i; j <= N; j += i) st[j] = 1;
            }
        }
        int ans = 0;
        for (int i = 1; i <= n; ++i) ans += !st[a[i]];
        cout << ans;
    }
    

    E. Smart Infants

    照着题目模拟就是,问题主要是要用对资料结构。 对于每个 kindergarden 我们需要一个可以高速插入、高速删除、高速查询最大值的容器。

    C++ 的 multiset 符合所需。 使用 c++ 的 multiset 要注意的一点是 set.erase(val) 会删除容器中所有值为 valentries,若只想删除一个值为valentry,要用 set.erase(set.find(val))

    即:对每次变换求所有集合最大值中的最小值。用s[]表示各个集合,m表示最大值集合,每次对集合元素删除加入。注意元素有可能相同,所以要用multiset.

    int main() { // try new nameing rules and Coding style
        cin.tie(nullptr)->sync_with_stdio(false);
        int N, Q;
        int M = 2e5;
        cin >> N >> Q;
    
        auto belong = vector<int>(N, -1);
        auto rating = vector<int>(N, -1);
        auto evenesses = multiset<int>();
        auto kdrgrtns = vector<multiset<int>>(M);
    
        for (int i = 0; i < N; ++i) {
            int A, B;
            cin >> A >> B;
            B--;
            rating[i] = A;
            belong[i] = B;
            kdrgrtns[B].insert(A);
        }
        for (auto k : kdrgrtns) {
            if (!k.empty())
                evenesses.insert(*k.rbegin());
        }
    
        while (Q--) {
            int C, D;
            cin >> C >> D;
            C--, D--;
    
            auto &kdrgrtn_src = kdrgrtns[belong[C]];
            auto &kdrgrtn_dst = kdrgrtns[D];
    
            evenesses.erase(evenesses.find(*kdrgrtn_src.rbegin()));
            kdrgrtn_src.erase(kdrgrtn_src.find(rating[C]));
            if (kdrgrtn_src.size() > 0)
                evenesses.insert(*kdrgrtn_src.rbegin());
    
            if (kdrgrtn_dst.size() > 0)
                evenesses.erase(evenesses.find(*kdrgrtn_dst.rbegin()));
            kdrgrtn_dst.insert(rating[C]);
            evenesses.insert(*kdrgrtn_dst.rbegin());
    
            belong[C] = D;
    
            cout << *evenesses.begin() << "
    ";
        }
    }
    

    F. Pond Skater

    Snuke,水上平衡车,住在一个矩形池塘,可以看成 H 列 W 行,(i, j) 表示第 i 列第 j 行。池塘里长着荷叶,荷叶是不能进入的。如果 cij 是 @,表示荷叶。如果 cij 是 .,表示不是荷叶。

    Snuke 每次可以向北、东、南、西的任意同一个方向移动一步到 K 步,但是不能通过荷叶,同时也不能移动到池塘外。

    给我们起点坐标 (x1, y1) 和终点坐标 (x2, y2),要求我们找到最小的移动步数。如果不能到达,输出 -1。


    Here 有一个博主写了很详细的分析

    这题马上让人想到是最短路径,于是就刻了一个 Dijkstra,然后就会 TLE。

    对于每个 vertex 我们都展开 4 * K 条边实在太多了,所幸我们可以剪枝。

    当我们在 (r, c),尝试用 dis[r][c] + 1 松弛 dis[r + k * dr][c + k * dc] 不成功时,我们不需要展开更大的 k,因为那些更远的点(即 k 更大)不可能透过目前的路径得到更佳的解。

    写成程式码就是在展开边的地方加入剪枝:

    // omit
    for (int k = 1; k <= K; k++) {
        // omit
        if (dis[r + k * dr][c + k * dc] < dis[r][c] + 1) break;
        // omit
    }
    

    你就能 AC 了。官方題解我是沒有看懂,這題網路上的題解都是 BFS + 剪枝,我是覺得挺神奇的啦,最短路徑不是應該想到 Dijkstra 嗎?還有人說此剪枝方法不適用 Dijkstra,只能用在 BFS 上 (┛ಠ_ಠ)┛彡┻━┻

    using ti3 =  tuple<int, int, int>;
    const int inf = 0x3f3f3f3f;
    int main() {
        cin.tie(nullptr)->sync_with_stdio(false);
        int H, W, K;
        cin >> H >> W >> K;
        int sr, sc, tr, tc;
        cin >> sr >> sc >> tr >> tc;
        sr--, sc--, tr--, tc--;
        vector<string> S(H);
        for (int i = 0; i < H; ++i) cin >> S[i];
    
        vector<ti3> nxt;
        nxt.push_back({+1, 0, 1});
        nxt.push_back({-1, 0, 1});
        nxt.push_back({0, +1, 1});
        nxt.push_back({0, -1, 1});
    
        vector<vector<int>> dis(H, vector<int>(W, inf));
        auto q = priority_queue<ti3, vector<ti3>, greater<ti3>>();
    
        dis[sr][sc] = 0;
        q.push({0, sr, sc});
    
        while (!q.empty()) {
            auto [d, r, c] = q.top(); q.pop();
            if (d > dis[r][c]) continue;
            for (auto &&[dr, dc, w] : nxt) {
                for (int k = 1; k <= K; ++k) {
                    int nr = r + k * dr;
                    int nc = c + k * dc;
                    if (nr < 0 || nr >= H) break;
                    if (nc < 0 || nc >= W) break;
                    if (S[nr][nc] == '@') break;
                    if (dis[nr][nc] < d + w) break;
                    if (dis[nr][nc] > d + w) {
                        dis[nr][nc] = d + w;
                        q.push({dis[nr][nc], nr, nc});
                    }
                }
            }
        }
    
        cout << (dis[tr][tc] == inf ? -1 : dis[tr][tc]);
    }
    

    The desire of his soul is the prophecy of his fate
    你灵魂的欲望,是你命运的先知。

  • 相关阅读:
    各国语言缩写列表,各国语言缩写-各国语言简称,世界各国域名缩写
    How to see log files in MySQL?
    git 设置和取消代理
    使用本地下载和管理的免费 Windows 10 虚拟机测试 IE11 和旧版 Microsoft Edge
    在Microsoft SQL SERVER Management Studio下如何完整输出NVARCHAR(MAX)字段或变量的内容
    windows 10 x64系统下在vmware workstation pro 15安装macOS 10.15 Catelina, 并设置分辨率为3840x2160
    在Windows 10系统下将Git项目签出到磁盘分区根目录的方法
    群晖NAS(Synology NAS)环境下安装GitLab, 并在Windows 10环境下使用Git
    使用V-2ray和V-2rayN搭建本地代理服务器供局域网用户连接
    windows 10 专业版安装VMware虚拟机碰到的坑
  • 原文地址:https://www.cnblogs.com/RioTian/p/15152417.html
Copyright © 2011-2022 走看看