竞赛 双周赛

这篇具有很好参考价值的文章主要介绍了竞赛 双周赛。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

第 108 场双周赛

2765. 最长交替子序列

分段

class Solution {
    public int alternatingSubarray(int[] nums) {
        int res = -1, n = nums.length;
        for (int i = 1; i < n; i++) {
            // 找每一段第一个
            if (nums[i] - nums[i - 1] == 1) {
                int left = i - 1, x = nums[left];
                while (i < n - 1 && nums[i + 1] == x + (i - left + 1) % 2) i++;
                res = Math.max(res, i - left + 1);
            }
        }
        return res;
    }
}

2766. 重新放置石块

class Solution {
    public List<Integer> relocateMarbles(int[] nums, int[] moveFrom, int[] moveTo) {
        Set<Integer> s = Arrays.stream(nums).boxed().collect(Collectors.toSet());
        for (int i = 0; i < moveFrom.length; ++i) {
            s.remove(moveFrom[i]);
            s.add(moveTo[i]);
        }
        return s.stream().sorted().toList();
    }
}

2767. 将字符串分割为最少的美丽子字符串

class Solution {
    String s;
    int INF = 0x3f3f3f3f;
    static Set<String> set = new HashSet<>();
    // 预处理所有 5 的幂的 二进制 表示
    static {        
        for(int i = 0; i < 8; i++){
            set.add(Integer.toBinaryString((int)Math.pow(5, i)));
        }
    }
    int[] cache;
    public int minimumBeautifulSubstrings(String s) {
        this.s = s;
        int n = s.length();
        cache = new int[n + 1];
        Arrays.fill(cache, -1);
        int res = backtrack(n);
        return res == INF ? -1 : res;
    }

    // 定义 backtrack(i) 表示分割 s[i:] 的最少数目
    public int backtrack(int i){
        if(i == 0) return 0;
        if(cache[i] >= 0) return cache[i];
        int res = INF;
        // 遍历集合,从右向左扩展,set 可以是 list
        for (String t : set) {
            int m = t.length();
            if (i >= m && t.equals(s.substring(i - m, i))) {
                res = Math.min(res, backtrack(i - m) + 1);
            }
        }

        // for(int j = i - 1; j >= 0; j--){
        //     if(s.charAt(j) != '0' && set.contains(s.substring(j, i))){
        //         res = Math.min(res, backtrack(j) + 1);
        //     }
        // }
        return cache[i] = res;
    }
}
class Solution {
    public int minimumBeautifulSubstrings(String s) {
        // 预处理所有 5 的幂的 二进制 表示
        // List<String> list = new ArrayList<>();
        Set<String> set = new HashSet();
        for(int i = 0; i < 8; i++){
            set.add(Integer.toBinaryString((int)Math.pow(5, i)));
        }
        int n = s.length(), INF = 0x3f3f3f3f;
        int[] f = new int[n + 1];
        Arrays.fill(f, INF);
        f[0] = 0;
        for(int i = 0; i <= n; i++){ // f 的下标
            if (f[i] == INF) continue;
            // 向右扩展
            for (String t : set) {
                int j = t.length() + i;
                if (j <= n && t.equals(s.substring(i, j)))
                    f[j] = Math.min(f[j], f[i] + 1);
            }
        }
        // for(int i = 1; i <= n; i++){ // f 的下标    
        //     if (s.charAt(i - 1) == '0') continue; // 剪枝
        //     // 当前 i 向左试着找
        //     for(int j = i - 1; j >= 0; j--){
        //         if(s.charAt(j) == '1' && set.contains(s.substring(j, i)))
        //             f[i] = Math.min(f[i], f[j] + 1);
        //     }
        // }
        return f[n] == INF ? -1 : f[n];
    }
}

2768. 黑格子的数目

块定义为网格图中 2 x 2 的一个子矩阵。对于 左上角格子为 [x, y] 的块,其中 0 <= x < m - 1 且 0 <= y < n - 1 ,包含坐标为 [x, y] ,[x + 1, y] ,[x, y + 1] 和 [x + 1, y + 1] 的格子。
任意一个点 (x, y),包含它的块为 [x-1, y-1], [x-1, y], [x, y-1], [x, y],其中坐标不能越界。

class Solution {
    public long[] countBlackBlocks(int m, int n, int[][] coordinates) {
        int[][] DIRS = {{-1,-1},{-1,0},{0,-1},{0,0}};
        
        Map<Integer, Integer> map = new HashMap<>();               
        for (int[] coor : coordinates) {
            for (int[] dir : DIRS) {
                int x = coor[0] + dir [0];
                int y = coor[1] + dir [1];
                if (x < 0 || y < 0 || x >= m - 1 || y >= n - 1) continue;                
                int index = x * n + y;
                map.merge(index, 1, Integer::sum);                          
            }
        }

        long[] res = new long[5];
        for(int value : map.values())
            res[value]++;
       

       res[0] = 1L * (m - 1) * (n - 1) - map.size();
        return res;
    }
}

第 107 场双周赛

2744. 最大字符串配对数目

class Solution {
    public int maximumNumberOfStringPairs(String[] words) {
        int res = 0;
        Set<String> vis = new HashSet();
        for (String s : words) {
            if (vis.contains(s)) res++;
            else vis.add(new StringBuffer(s).reverse().toString());
        }
        return res;
    }
}

2746. 字符串连接删减字母

class Solution {
    int n;
    int[][] arr;
    int[][][] memo;
    public int minimizeConcatenatedLength(String[] words) {
        int res = Arrays.stream(words).mapToInt(String::length).sum();
        n = words.length;
        // 只需要首尾两个字符
        arr = new int[n][2];
        for (int i = 0; i < n; i++) {
            String w = words[i];
            arr[i] = new int[]{w.charAt(0) - 'a', w.charAt(w.length() - 1) - 'a'};
        }
        memo = new int[n][26][26];
        for (int[][] a : memo) for (int[] b : a) Arrays.fill(b, 1);
        return res + dfs(1, arr[0][0], arr[0][1]);

    }
    // 最多可以减少的字符
    int dfs(int i, int b, int a) {
        if (i == n) return 0;
        int u = arr[i][0];
        int v = arr[i][1];
        if (memo[i][b][a] < 1) return memo[i][b][a];
        // 接前、接后
        return memo[i][b][a] = Math.min(dfs(i + 1, u, a) + (v == b ? -1 : 0), dfs(i + 1, b, v) + (u == a ? -1 : 0));
    }
}

2747. 统计没有收到请求的服务器数目

class Solution {
    public int[] countServers(int n, int[][] logs, int x, int[] queries) {        
        int nq = queries.length;        
        var id = new Integer[nq];
        Arrays.setAll(id, i -> i);
        Arrays.sort(id, (i, j) -> queries[i] - queries[j]);
        
        int m = logs.length;
        Arrays.sort(logs, (a, b) -> a[1] - b[1]); // 按照 time 排序

        int[] res = new int[nq], cnt = new int[n + 1];
        int outOfRange = n, left = 0, right = 0;
        for (int i : id) {
            // 进入窗口
            for (; right < m && logs[right][1] <= queries[i]; cnt[logs[right++][0]]++)             
                if(cnt[logs[right][0]] == 0) outOfRange--;
            // 离开窗口
            for (; left < m && logs[left][1] < queries[i] - x; cnt[logs[left++][0]]--) 
                if (cnt[logs[left][0]] == 1) outOfRange++;
            res[i] = outOfRange;
        }
        return res;
    }
}

第 103 场双周赛

BFS / DFS, 树状数组

2658. 网格图中鱼的最大数目

// class Solution {
//     int[] dirs = {1,0,-1,0,1};
//     public int findMaxFish(int[][] grid) {
//         int m = grid.length, n = grid[0].length;
//         int res = 0;
//         for (int i = 0; i < m; i++) {
//             for (int j = 0; j < n; j++) {
//                 if (grid[i][j] > 0)
//                     res = Math.max(res, bfs(grid, i, j));
//             }
//         }
//         return res;
//     }
    
//     int bfs(int[][] grid, int i, int j) {
//         int res = 0;
//         Deque<int[]> q = new LinkedList();
//         q.offer(new int[]{i, j});

//         while (!q.isEmpty()) {
//             i = q.peek()[0]; j = q.poll()[1];
//             res += grid[i][j];
//             grid[i][j] = 0;
//             for (int k = 0; k < 4; k ++) {
//                 int x = i + dirs[k], y = j + dirs[k + 1];
//                 if (x < 0 || x >= grid.length || y < 0 || y >= grid[0].length || grid[x][y] == 0) continue;
//                 q.offer(new int[]{x, y});
//             }
//         }
//         return res;
//     }
// }

class Solution {
    private final static int[][] DIRS = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
    int m, n;
    public int findMaxFish(int[][] grid) {
        m = grid.length; n = grid[0].length;
        int ans = 0;
        for (int i = 0; i < m; ++i)
            for (int j = 0; j < n; ++j)
                ans = Math.max(ans, dfs(grid, i, j));
        return ans;
    }

    private int dfs(int[][] grid, int x, int y) {        
        if (x < 0 || x >= m || y < 0 || y >= n || grid[x][y] == 0)
            return 0;
        int sum = grid[x][y];
        grid[x][y] = 0; // 标记成访问过
        for (var d : DIRS) // 四方向移动
            sum += dfs(grid, x + d[0], y + d[1]);
        return sum;
    }
}

2659. 将数组清空

方法一:树状数组

query(i, j) 表示在 [i, j] 中的被删除的元素个数。
上一个被删除的位置为 pre(初始为 1),当前需要删除的位置为 i。
假设现在共删除了 k 个数,从 pre 到 i 的移动次数 step:
s t e p = { i − p r e − q u e r y ( p r e , i ) p r e ≤ i n − ( p r e − i ) − ( k − q u e r y ( i , p r e − 1 ) ) i < p r e step=\begin{cases} i − pre − query(pre, i) & pre ≤ i \\ n − (pre − i) - (k - query(i, pre - 1)) & i < pre \\ \end{cases} step={iprequery(pre,i)n(prei)kquery(i,pre1))preii<pre

class Solution {
    public long countOperationsToEmptyArray(int[] nums) {
        int n = nums.length;
        var id = new Integer[n];
        Arrays.setAll(id, i -> i);
        Arrays.sort(id, (i, j) -> nums[i] - nums[j]);

        long ans = n; // 先把 n 计入答案
        var t = new BIT(n + 1); // 下标从 1 开始
        int pre = 1; // 上一个最小值的位置,初始为 1
        for (int k = 0; k < n; ++k) {
            int i = id[k] + 1; // 下标从 1 开始
            if (i >= pre) // 从 pre 移动到 i,跳过已经删除的数
                ans += i - pre - t.query(pre, i);
            else // 从 pre 移动到 n,再从 1 移动到 i,跳过已经删除的数
                ans += n - pre + i - k + t.query(i, pre - 1);                
            t.inc(i); // 删除 i
            pre = i;
        }
        return ans;
    }
}

// 树状数组模板
class BIT {
    private final int[] tree;

    public BIT(int n) {
        tree = new int[n];
    }

    // 将下标 i 上的数加一
    public void inc(int i) {
        while (i < tree.length) {
            ++tree[i];
            i += i & -i;
        }
    }

    // 返回闭区间 [1, i] 的元素和
    public int sum(int x) {
        int res = 0;
        while (x > 0) {
            res += tree[x];
            x &= x - 1;
        }
        return res;
    }

    // 返回闭区间 [left, right] 的元素和
    public int query(int left, int right) {
        return sum(right) - sum(left - 1);
    }
}

方法二:

如果第 k 次要删除的元素在第 k−1 次要删除的元素的左侧,那么必须多走一整圈,移动次数为 n−k。累加,即为总的移动次数。

最后如果剩下若干递增元素,直接一股脑删除,无需任何移动次数。

class Solution {
    public long countOperationsToEmptyArray(int[] nums) {
        int n = nums.length;
        var id = new Integer[n];
        Arrays.setAll(id, i -> i);
        Arrays.sort(id, (i, j) -> nums[i] - nums[j]);

        long ans = n; // 先把 n 计入答案
        for (int k = 1; k < n; ++k)
            if (id[k] < id[k - 1]) // 必须多走一整圈
                ans += n - k; // 减去前面删除的元素个数
        return ans;
    }
}

第 102 场双周赛

2642. 设计可以求最短路径的图类

方法一:Dijkstra

定义 start 为起点,dis[i] 表示从 start 到 i 的最短路的长度。初始时 dis[start] = 0,其余 dis[i] 为 ∞。

首先,从 start 出发,更新邻居的最短路。

下一步,寻找除去 start 的 dis 的最小值,设这个点为 x,那么 dis[x] 就已经是从 start 到 x 的最短路的长度了。

由于在寻找 dis 的最小值时,需要排除在前面的循环中找到的 x(因为已经更新 x 到其它点的最短路了,无需反复更新),可以用一个vis 数组标记这些 x。

以上,通过数学归纳法,可以证明每次找到的未被标记的 dis 的最小值就是最短路。

由于输入的图最坏是稠密图,所以采用邻接矩阵实现。

class Graph {
    private static final int INF = Integer.MAX_VALUE / 2; // 防止更新最短路时加法溢出

    private int[][] g;

    public Graph(int n, int[][] edges) {
        g = new int[n][n]; // 邻接矩阵(初始化为无穷大,表示 i 到 j 没有边)
        for (int i = 0; i < n; ++i)
            Arrays.fill(g[i], INF);
        for (var e : edges)
            g[e[0]][e[1]] = e[2]; // 添加一条边(输入保证没有重边)
    }

    public void addEdge(int[] e) {
        g[e[0]][e[1]] = e[2]; // 添加一条边(输入保证这条边之前不存在)
    }

    // 朴素 Dijkstra 算法
    public int shortestPath(int start, int end) {
        int n = g.length;
        var dis = new int[n]; // 从 start 出发,到各个点的最短路,如果不存在则为无穷大
        Arrays.fill(dis, INF);
        dis[start] = 0;
        var vis = new boolean[n];
        for (;;) {
            // 找到当前最短路,去更新它的邻居的最短路
            // 根据数学归纳法,dis[x] 一定是最短路长度
            int x = -1;
            for (int i = 0; i < n; ++i)
                if (!vis[i] && (x < 0 || dis[i] < dis[x]))
                    x = i;
            if (x < 0 || dis[x] == INF) // 所有从 start 能到达的点都被更新了
                return -1;
            if (x == end) // 找到终点,提前退出
                return dis[x];
            vis[x] = true; // 标记,在后续的循环中无需反复更新 x 到其余点的最短路长度
            for (int y = 0; y < n; ++y)
                dis[y] = Math.min(dis[y], dis[x] + g[x][y]); // 更新最短路长度
        }
    }
}

方法二:Floyd

Floyd 本质是动态规划。由于这个动态规划的状态定义不是很好想出来,所以我就直接描述算法了:

定义 d[k][i][j] 表示从 i 到 j 的最短路长度,并且从 i 到 j 的路径上的中间节点(不含 i 和 j)的编号至多为 k。

分类讨论:

如果 i 到 j 的路径上的节点编号没有 k,那么按照定义 d[k][i][j] = d[k-1][i][j]。
如果 i 到 j 的路径上的节点编号有 k,那么可以视作先从 i 到 k,再从 k 到 j。由于 i 到 k 和 k 到 j 的中间节点都没有 k,所以有 d[k][i][j] = d[k-1][i][k] + d[k-1][k][j]。
取最小值,得

d[k][i][j]=min(d[k−1][i][j],d[k−1][i][k]+d[k−1][k][j])

初始值 d[0][i][j] 为原图中 i 到 j 的边长,如果不存在则为 ∞。最终 i 到 j 的最短路长度为 d[k-1][i][j]。

代码实现时,第一个维度可以优化掉,即

d[i][j]=min(d[[i][j],d[i][k]+d[k][j])

对于 addEdge 操作,记 x=from,y=to 如果 edgeCode≥d[x][y],则无法更新任何点对的最短路。否则枚举所有 d[i][j],尝试看看能否更新成更小,即 i—x-y—j 是否更短:

d[i][j]=min(d[i][j],d[i][x]+edgeCode+d[y][j])

由于当 i=x 或 j=y 时,需要用到 d[i][i] 这样的值,所以初始化的时候,d[i][i] 要置为 0。文章来源地址https://www.toymoban.com/news/detail-527835.html

class Graph {
    private static final int INF = Integer.MAX_VALUE / 3; // 防止更新最短路时加法溢出

    private int[][] d;

    public Graph(int n, int[][] edges) {
        d = new int[n][n]; // 邻接矩阵(初始化为无穷大,表示 i 到 j 没有边)
        for (int i = 0; i < n; ++i) {
            Arrays.fill(d[i], INF);
            d[i][i] = 0;
        }
        for (var e : edges)
            d[e[0]][e[1]] = e[2]; // 添加一条边(输入保证没有重边和自环)
        for (int k = 0; k < n; ++k)
            for (int i = 0; i < n; ++i)
                for (int j = 0; j < n; ++j)
                    d[i][j] = Math.min(d[i][j], d[i][k] + d[k][j]);
    }

    public void addEdge(int[] e) {
        int x = e[0], y = e[1], w = e[2], n = d.length;
        if (w >= d[x][y]) // 无需更新
            return;
        for (int i = 0; i < n; ++i)
            for (int j = 0; j < n; ++j)
                d[i][j] = Math.min(d[i][j], d[i][x] + w + d[y][j]);
    }

    public int shortestPath(int start, int end) {
        int ans = d[start][end];
        return ans < INF / 3 ? ans : -1;
    }
}

到了这里,关于竞赛 双周赛的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 蓝桥杯 第一场算法双周赛题解(前五题)

    题目链接在此😁:第 1 场算法双周赛 - 蓝桥云课 为什么只有前5道题的题解呢?(懂的都懂~🤐) 考察:简单逻辑判断 问题描述 小蓝和小桥玩斗地主,小蓝只剩四张牌了,他想知道是否是“三带一”牌型。 所胃三带一”牌型,即四张手牌中,有三张牌一样,另外一张不与其

    2024年02月08日
    浏览(45)
  • 蓝桥杯1024第 2 场算法双周赛题解+Ac代码

    提醒:篇幅可能有点长,为了方便,大家可以直接看目录快速查找想要的内容 1.新生【算法赛】 - 蓝桥云课 (lanqiao.cn) input: output: 1.对于每一块地板,如果能被凑出来,那么一定是2*3地砖组合出来的,无论2*3地砖怎么放都为6的倍数,故长为n,宽为m的地板,n*m%6==0一定成立 2.这里

    2024年02月06日
    浏览(43)
  • 「蓝桥·算法双周赛」第一场公开赛【待补题填坑】

    给定四个字符,判断是否其中有三个相同,另一个与他们不同  二叉树性质问题,不了解二叉树也完全可以做。 要注意的是每次都从第一行的第一个点开始走,给一个字符串按照它走,输出最后的结果就行。 往左走坐标就变成了2*pos-1,往右就变成了2*pos 画个树理解一下就好

    2024年02月07日
    浏览(51)
  • 零基础!无门槛!高额现金奖励!优秀的大学生都在打这场算法双周赛

       spacespace     大家好,我是执梗。在蓝桥杯中获得过十三届 Java B 组国一以及十四届 C++ B 组的国一。今天主要为大家带来一个好消息,蓝桥杯将为各位喜爱算法的小伙伴带来全新的算法双周赛。如果你热爱算法竞赛,或者准备参加十五届的蓝桥杯比赛,那么一定不要错过

    2024年02月08日
    浏览(62)
  • C++ 算法竞赛、04 周赛篇 | AcWing 第5场周赛

    竞赛 - AcWing 3726. 调整数组 - AcWing题库 简单题,判断奇偶数是否同时存在 3727. 乘方相加 - AcWing题库 记录 每个数据 的 k 进制 各个位数的值 保存到数组,题目要求每位最多为 1,超过 1 则无法达到 3728. 城市通电 - AcWing题库 图是稠密图,用朴素版Prim求, (O(n^2)) 每点建立发电站

    2024年02月09日
    浏览(71)
  • C++ 算法竞赛、05 周赛篇 | AcWing 第85场周赛

    竞赛 - AcWing 4791. 死或生 - AcWing题库 简单题 4792. 最大价值 - AcWing题库 贪心,先找到最大价值的字母,往最后面插最大的 4793. 危险程度 - AcWing题库 把图分成若干个连通块,每个连通块假设有 k 个点,最多会反应 k - 1 次 因此题目转变为求连通块数量,假设为 t,答案就是 (2^

    2024年02月09日
    浏览(42)
  • C++ 算法竞赛、08 周赛篇 | AcWing 第94场周赛 ⭐

    4870. 装物品 - AcWing题库 4870. 装物品 - AcWing题库 巨简单题 4871. 最早时刻 - AcWing题库 考查堆优化版迪杰斯特拉变形 越早到达,越早离开 = 每个点维护一个最早到达时刻 如果 delay 小于 0,就不能用迪杰斯特拉算法 4872. 最短路之和 - AcWing题库 最终结果可能是 (500^2 * 10^5) 可能会

    2024年02月08日
    浏览(49)
  • C++ 算法竞赛、07 周赛篇 | AcWing 第120场周赛

    竞赛 - AcWing 5146. 最大GCD - AcWing题库 不难发现,最大公约数的条件是 (GCD(lfloor frac{n}{2} rfloor ,lfloor frac{n}{2} rfloor * 2)) 5147. 数量 - AcWing题库 不含 4 和 7 以外 (Rightarrow) 只含 4 和 7,每位只有两种情况,最多到 1e9,即 (2^9) 个情况,爆搜枚举即可 AcWing 5148. 字符串匹配 -

    2024年02月08日
    浏览(42)
  • C++ 算法竞赛、02 周赛篇 | AcWing 第2场周赛

    竞赛 - AcWing AcWing 3626. 三元一次方程 - AcWing 两层循环 3627. 最大差值 - AcWing题库 考查贪心,所有输入的不是0的数排序,每次操作取最大的数++,由于每个数最大可以是1e9,int可能溢出,需要用 long long 3628. 边的删减 - AcWing题库 刚开始有点傻,打算用克鲁斯卡尔生成最小生成树

    2024年02月10日
    浏览(38)
  • C++ 算法竞赛、03 周赛篇 | AcWing 第4场周赛

    竞赛 - AcWing 3694. A还是B - AcWing题库 简单题 3695. 扩充序列 - AcWing题库 考查递归。可以发现最终序列除中点,左右两段都是相等的,可以依据这个特性来递归 超级长的序列缩小 (log_2n) 次,每次将 k 坐标映射到缩小的各个序列上,k肯定是其中一个序列的中点 3696. 构造有向无环

    2024年02月09日
    浏览(39)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包