牛客周赛 Round 1 解题报告 | 珂学家 | 分类计数 + 同余DP

news2024/9/28 9:27:15

前言

生于生时,亡于亡刻。遵从自心,尽人之事。


整体评价

终于等来了侧重面试的比赛,而且题量刚刚好,不超纲,不涉及算法竞赛。

第一场的比赛,感觉题目出的比较典,A是简单模拟,B则是计数题,C则是贪心思路,D是经典的同余DP。

唯一吐槽的是,牛客好像当前只JDK 8, 用不了var.


欢迎关注

珂朵莉 牛客周赛专栏

珂朵莉 牛客小白月赛专栏


A. 游游画U

找规律题吧,就是找到底托,中间对等分开,然后往两边靠齐。

而N,则限定了最终图的长宽高,还有就是‘*’的长度

import java.io.BufferedInputStream;
import java.util.Arrays;
import java.util.Scanner;

public class Main {

    public static void main(String[] args) {
        Scanner sc = new Scanner(new BufferedInputStream(System.in));
        int n = sc.nextInt();
        
        // 定义结果的画布
        char[][] res = new char[4 * n][4 * n];
        
        // 前面的3*n行
        for (int i = 0; i < 3 * n; i++) {
            Arrays.fill(res[i], '.');
            for (int j = 0; j < n; j++) {
                res[i][j] = res[i][4*n - 1 - j] = '*';
            }
        }
        
        // 最下面的n行
        for (int i = 3 * n; i < 4 * n; i++) {
            int offset = i + 1 - 3 * n;
            Arrays.fill(res[i], '.');
            for (int j = 0; j < n; j++) {
                res[i][offset + j] = res[i][4 * n - 1 - offset - j] = '*';
            }
        }
        
        // 输出内容
        for (int i = 0; i < 4 * n; i++) {
            System.out.println(new String(res[i]));
        }


    }

}

B. 游游的数组染色

先按同值进行分类,然后内部按颜色进行计数

m a p [ v a l u e ] [ c o l o r ] {map[value][color]} map[value][color]

那最终的结果为

∑ v i ∑ c j ∈ C m a p [ v i ] [ c j ] ∗ ( ∑ k ∈ C m a p [ v i ] [ c k ] − m a p [ v i ] [ c j ] ) \sum_{v_i} \sum_{c_j \in C} map[v_i][c_j] * (\sum_{k\in C} map[v_i][c_k] - map[v_i][c_j]) vicjCmap[vi][cj](kCmap[vi][ck]map[vi][cj])

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;

public class Main {

    public static void main(String[] args) {
        AReader sc = new AReader();
        int n = sc.nextInt();
        int[] arr = new int[n];
        for (int i = 0; i < n; i++) {
            arr[i] = sc.nextInt();
        }
        char[] str = sc.next().toCharArray();

        Map<Integer, TreeMap<Character, Integer>> range = new HashMap<>();
        for (int i = 0; i < n; i++) {
            if (!range.containsKey(arr[i])) {
                range.put(arr[i], new TreeMap<>());
            }
            range.get(arr[i]).merge(str[i], 1, Integer::sum);
        }

        long ans = 0;
        for (Map.Entry<Integer, TreeMap<Character, Integer>> kv: range.entrySet()) {
            TreeMap<Character, Integer> ts = kv.getValue();
            long acc = 0;
            for (Map.Entry<Character, Integer> kv2: ts.entrySet()) {
                acc += kv2.getValue();
            }

            for (Map.Entry<Character, Integer> kv2: ts.entrySet()) {
                ans += (long)(acc - kv2.getValue()) * kv2.getValue();
            }
        }

        System.out.println(ans / 2);
    }

    static
    class AReader {
        private BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        private StringTokenizer tokenizer = new StringTokenizer("");
        private String innerNextLine() {
            try {
                return reader.readLine();
            } catch (IOException ex) {
                return null;
            }
        }
        public boolean hasNext() {
            while (!tokenizer.hasMoreTokens()) {
                String nextLine = innerNextLine();
                if (nextLine == null) {
                    return false;
                }
                tokenizer = new StringTokenizer(nextLine);
            }
            return true;
        }
        public String nextLine() {
            tokenizer = new StringTokenizer("");
            return innerNextLine();
        }
        public String next() {
            hasNext();
            return tokenizer.nextToken();
        }
        public int nextInt() {
            return Integer.parseInt(next());
        }

        public long nextLong() {
            return Long.parseLong(next());
        }
        
    }

}

#include <bits/stdc++.h>

using namespace std;

int main() {
    
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    
    int n;
    cin >> n;
    
    vector<int> arr(n);
    for (int i = 0; i < n; i++) {
        cin >> arr[i];
    }
    string s;
    cin >> s;
    map<int, int> h1, h2;
    for (int i = 0; i< n; i++) {
        char c = s[i];
        if (c == 'B') {
            h2[arr[i]]++;
        } else {
            h1[arr[i]]++;
        }
    }
    
    long long res = 0LL;
    for (auto iter = h1.begin(); iter != h1.end();  iter++) {
        if (h2.find(iter->first) != h2.end()) {
            res += (long long)h2[iter->first] * (iter->second);
        }
    }
    cout << res << endl;
    
    return 0;
}

C. 游游的交换字符

分类讨论,即构造1开头的串,和0开头的串,两者那个代价小。

一旦确定分头,实际上代价就定下来,重要的是如何计算。

比如当前串,以及构建好了’01…1’, 你要寻找下一个‘0’, 则需要多少代价呢?

这个时候,就是从原串中,下一个‘0’之前有几个’1’呢

同理,‘1’也是统计前置几个‘0’

那这个动态有变动的统计0-1该怎么处理呢?

我们可以尝试引入 0-1 树状数组

就是有一个单独统计‘1’的位置的树状数组,一个统计‘0’的树状数组

前置的01构建完后,就删掉对应的01位置即可。

import java.io.BufferedInputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

public class Main {

    static class BIT {
        int n;
        int[] arr;
        public BIT(int n) {
            this.n = n;
            this.arr = new int[n + 1];
        }
        void update(int p, int d) {
            while (p <= n) {
                arr[p] += d;
                p += p & -p;
            }
        }
        int query(int p) {
            int res = 0;
            while (p > 0) {
                res += arr[p];
                p -= p & -p;
            }
            return res;
        }
    }

    // *)
    public static long solve(char[] buf, char s) {
        // 找到最近的0
        int n = buf.length;
        BIT bit0 = new BIT(n);
        BIT bit1 = new BIT(n);

        List<Integer> list0 = new ArrayList<>();
        List<Integer> list1 = new ArrayList<>();
        for (int i = 0; i < n; i++) {
            if (buf[i] == '0') {
                list0.add(i + 1);
                bit0.update(i + 1, 1);
            } else {
                list1.add(i + 1);
                bit1.update(i + 1, 1);
            }
        }

        long ans = 0l;

        if (s == '0') {
            if (list0.size() < list1.size()) return Long.MAX_VALUE;

            for (int i = 0; i < n; i++) {
                if (i % 2 == 0) {
                    int idx = list0.get(i/2);
                    int delta = bit1.query(idx);
                    bit0.update(idx, -1);

                    ans += delta;
                } else {
                    int idx = list1.get(i/2);
                    int delta = bit0.query(idx);
                    bit1.update(idx, -1);
                    ans += delta;
                }
            }

        } else {

            if (list1.size() < list0.size()) return Long.MAX_VALUE;

            for (int i = 0; i < n; i++) {
                if (i % 2 == 0) {
                    int idx = list1.get(i/2);
                    int delta = bit0.query(idx);
                    bit1.update(idx, -1);

                    ans += delta;
                } else {
                    int idx = list0.get(i/2);
                    int delta = bit1.query(idx);
                    bit0.update(idx, -1);
                    ans += delta;
                }
            }
        }

        return ans;
    }

    public static void main(String[] args) {
        Scanner sc = new Scanner(new BufferedInputStream(System.in));
        char[] buf = sc.next().toCharArray();

        long res = Math.min(solve(buf.clone(), '0'), solve(buf.clone(), '1'));

        System.out.println(res);
    }

}

不过这个解法,应该是写复杂了。

直接贪心即可

就是 ∑ i = 0 i = ( n + 1 ) / 2 ( c u r r e n t i − e x p e c t i ) {\sum_{i=0}^{i=(n+1)/2} (current_i - expect_i)} i=0i=(n+1)/2(currentiexpecti)

c u r r e n t i 是第 i 个 1 所在的位子, e x p e c t i 是被期望的位子 current_i是第i个1所在的位子,expect_i是被期望的位子 currenti是第i1所在的位子,expecti是被期望的位子

import java.io.BufferedInputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

public class Main {

    // *)
    public static long solve(char[] buf, char s) {
        // 找到最近的0
        int n = buf.length;
        
        List<Integer> list0 = new ArrayList<>();
        List<Integer> list1 = new ArrayList<>();
        for (int i = 0; i < n; i++) {
            if (buf[i] == '0') {
                list0.add(i);
            } else {
                list1.add(i);
            }
        }

        long ans = 0l;

        if (s == '0') {
            if (list0.size() < list1.size()) return Long.MAX_VALUE;
            for (int i = 0; i < list0.size(); i++) {
                ans += Math.abs(2 * i - list0.get(i)); 
            }
        } else {
            if (list1.size() < list0.size()) return Long.MAX_VALUE;
            for (int i = 0; i < list1.size(); i++) {
                ans += Math.abs(2 * i - list1.get(i)); 
            }
        }

        return ans;
    }

    public static void main(String[] args) {
        Scanner sc = new Scanner(new BufferedInputStream(System.in));
        char[] buf = sc.next().toCharArray();

        long res = Math.min(solve(buf.clone(), '0'), solve(buf.clone(), '1'));

        System.out.println(res);
    }

}
#include <bits/stdc++.h>

using namespace std;

struct FastIO {
    FastIO() {
        ios::sync_with_stdio(false);
        cin.tie(nullptr);
        cout.tie(nullptr);
    }
}_fastIo;


int main() {
    string s;
    cin >> s;
    
    int n = s.length();
    vector<int> list0;
    for (int i = 0; i < n; i++) {
        if (s[i] == '0') list0.push_back(i);
    }
    
    long long cost = 0x3f3f3f3f;
    if (n % 2 == 0) {
        if (list0.size() == n / 2) {
            long long tmp1 = 0, tmp2 = 0;
            for (int i = 0; i < n / 2; i++) {
                tmp1 += abs(list0[i] - (i * 2));   
                tmp2 += abs(list0[i] - (i * 2 + 1));
            }
            cost = min(tmp1, tmp2);
        }
    } else {
        if (list0.size() == n / 2 + 1) {
            long long tmp1 = 0;
            for (int i = 0; i < n / 2 + 1; i++) {
                tmp1 += abs(list0[i] - (i * 2));   
            }
            cost = tmp1;
        } else if (list0.size() == n / 2) {
            long long tmp2 = 0;
            for (int i = 0; i < n / 2; i++) {
                tmp2 += abs(list0[i] - (i * 2 + 1));
            }
            cost = tmp2;
        }
    }

    cout << cost << endl;
    
    return 0;
}

D. 游游的9的倍数

经典的同余DP

因为求的是9的倍数,而数字串前缀 S i = a 0 a 1 . . . a i = b 0 ∗ 9 x + b 1 ∗ 9 x − 1 . . . + b i ∗ 9 0 S_i = a_0a_1...a_i = b_0 * 9^x + b_1 * 9^{x-1}... + b_i * 9^0 Si=a0a1...ai=b09x+b19x1...+bi90

S i a i + 1 = 10 ∗ b 0 ∗ 9 x + 10 ∗ b 1 ∗ 9 x − 1 . . . + 10 ∗ b i ∗ 9 0 + a i + 1 = 10 ∗ b i + a i + 1 S_ia_{i+1} = 10 * b_0 * 9^x + 10 * b_1 * 9^{x-1}... + 10 * b_i * 9^0 + a_{i+1} = 10 * b_i + a_{i+1} Siai+1=10b09x+10b19x1...+10bi90+ai+1=10bi+ai+1

所以我们令

o p t [ i ] [ j ] , 前 i 元素中,构建对 9 余数为 j 的总个数 opt[i][j], 前i元素中,构建对9余数为j的总个数 opt[i][j],i元素中,构建对9余数为j的总个数

状态转移为

o p t [ i + 1 ] [ ( j ∗ 10 + a i + 1 ) % 9 ] = o p t [ i ] [ ( j ∗ 10 + a i + 1 ) % 9 ] + o p t [ i ] [ j ] {opt[i+1][(j*10+a_{i+1}) \% 9] = opt[i][(j*10+a_{i+1})\%9] + opt[i][j]} opt[i+1][(j10+ai+1)%9]=opt[i][(j10+ai+1)%9]+opt[i][j]

当然这边对空集合的处理,有个小技巧,就是单独加1

o p t [ i + 1 ] [ a i + 1 % 9 ] + = 1 opt[i+1][a_{i+1}\%9] += 1 opt[i+1][ai+1%9]+=1

可以借助滚动数组来优化DP的空间

复杂度分析,时间 O ( 9 ∗ n ) O(9*n) O(9n), 空间复杂度为 O ( 20 ) O(20) O(20)

import java.io.BufferedInputStream;
import java.util.Arrays;
import java.util.Scanner;

public class Main {

    public static void main(String[] args) {
        Scanner sc = new Scanner(new BufferedInputStream(System.in));
        char[] buf = sc.next().toCharArray();

        long mod = 10_0000_0007l;
        long[][] opt = new long[2][9];
        opt[0][0] = 0l;

        int prev = 0, next = 1;
        for (int i = 0; i < buf.length; i++) {
            int p = buf[i] - '0';

            // 添加/不添加
            Arrays.fill(opt[next], 0);

            for (int j = 0; j < 9; j++) {
                opt[next][j] = opt[prev][j];
            }
            for (int j = 0; j < 9; j++) {
                opt[next][(j * 10 + p) % 9] += opt[prev][j];
                opt[next][(j * 10 + p) % 9] %= mod;
            }

            opt[next][p % 9] = (opt[next][p % 9] + 1) % mod;

            prev = 1 - prev;
            next = 1 - next;
        }

        System.out.println(((opt[prev][0]) % mod + mod) % mod);

    }


}
#include <bits/stdc++.h>

using namespace std;

using int64 = long long;

int main() {
    
    string s;
    cin >> s;
    
    int64 mod = 1'000'000'000 + 7;
    


    int64 dp[2][9];
    memset(dp[0], 0, sizeof(dp[0]));
    
    
    int prev = 0, next = 1;
    for (int i = 0; i < s.length(); i++) {
        memset(dp[next], 0, sizeof(dp[next]));
        char c = s[i];
        
        int d = c - '0';
        for (int j = 0; j < 9; j++) {
            dp[next][j] = (dp[next][j] + dp[prev][j]) % mod;
            dp[next][(j + d) % 9] = (dp[next][(j + d) % 9] + dp[prev][j]) % mod;
        }
        
        dp[next][d % 9] = (dp[next][d % 9] + 1) % mod;
        
        prev = 1 - prev;
        next = 1 - next;
    }
    
    cout << dp[prev][0] << endl;

    return 0;
}

如果9是个变量k,那其实也是同一种套路。

如果此题不用DP,能否解呢? 感觉有,因为9做为除数比较特殊,它打破了字符串的顺序限制。


写在最后

没有绝对的善意,关切的目光中也会掺杂恶意的期待。

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1379541.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

NX二次开发PK获取对象类型

PK_ENTITY_ask_class(),获取对象类型建议用这个函数&#xff0c;比较通用&#xff0c;包含所有对象类型&#xff0c;可以替代UF_MODL_ask_edge_type(),UF_MODL_ask_body_type(),UF_MODL_ask_face_type()等函数 PK_ENTITY_t entity; PK_CLASS_t PK_TYPE; PK_ENTITY_ask_class(e…

玩转Mysql 六(MySQL数据存储结构)

一路走来&#xff0c;所有遇到的人&#xff0c;帮助过我的、伤害过我的都是朋友&#xff0c;没有一个是敌人。如有侵权&#xff0c;请留言&#xff0c;我及时删除&#xff01; 一、MySQL数据存储结构解析 1、mysql数据存储结构的组成 ​ 从 InnoDB 逻辑存储结构来看&a…

HandlerInterceptor拦截器 postHandle执行addHeader无效,postHandle执行setStatus无效的解决方案

问题描述 想在postHandle方法里执行addHeader方法来补充一些Header信息&#xff08;如分页信息&#xff09;&#xff0c;但是最后执行却未如期显示 拦截器源码 import com.zhangziwa.practisesvr.utils.response.ResponseContext; import jakarta.servlet.http.HttpServletR…

【降龙算法】基于QT插件机制实现一个机器视觉算法小框架

机器视觉行业有各种各样的拖拉拽框架&#xff0c;也叫做低代码平台&#xff0c;例如国内海康的VisionMaster&#xff1a; 一个机器视觉框架需要包含各种算法模块&#xff0c;日志窗口&#xff0c;图像显示窗口等等&#xff0c;【降龙算法】就是做了一个入门级的机器视觉算法框…

What does `HandlerInterceptor` do?

HandlerInterceptor 是 SpringMVC 中的一个接口&#xff0c;在SpringMVC应用中它提供了一种实现应用级拦截器的机制。 第1步&#xff1a;引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web<…

自动化测试框架pytest系列之8个常用的装饰器函数

自动化测试框架pytest系列之基础概念介绍(一)-CSDN博客 自动化测试框架pytest系列之21个命令行参数介绍(二)-CSDN博客 自动化测试框架pytest系列之强大的fixture功能&#xff0c;为什么fixture强大&#xff1f;一文拆解它的功能参数。(三)-CSDN博客 接上文 3.5 pytest的8…

当一堆数据差异过大如何选?

我们通过采样获得一对数组&#xff0c;但是他们差异过大&#xff0c;所以我们选择进行一次滤除。 先看基本概念&#xff1a; 移动平均&#xff08;Moving Average&#xff09;&#xff1a; 计算每个数据点及其相邻数据点的平均值&#xff0c;可以使用不同的窗口大小。这有助于…

获取 Dll 模块的加载字符串资源

概要 获取 Dll 模块中加载的字符串资源&#xff0c;可以通过 LoadString 实现。这个函数可以用于在不同版本索引系统字符串&#xff0c;对于一些根据名称操作系统菜单的功能&#xff0c;可以使用这种方法动态获取系统模块当前的加载字符串。 LoadStringW 从与指定模块关联的可…

Linux中断 -- 中断应答、嵌套、

接上文&#xff0c;本文继续介绍Linux软件部分逻辑。 参考内核版本&#xff1a;kernel-4.19 目录 1.中断信号在各级中断控制器中的应答 2.supports_deactivate_key意义 3.中断嵌套 1.中断信号在各级中断控制器中的应答 本章主要从内核软件层面来看各中断控制器对中断信号处…

反敏捷宣言

很多时候&#xff0c;敏捷在实践中并没有帮助团队更好的完成工作&#xff0c;而是成为了某种障碍以及僵化的流程。原文: The Anti-Agile Manifesto 警告1: 如果你是敏捷教练或Scrum Master或任何其他形式的敏捷支持者&#xff0c;本文的很多内容都会让你不爽。本文的目的之一是…

Spring MVC组件

1.DispatcherServlet前端控制器 用户请求到达前端控制器&#xff0c;它就相当于mvc模式中的c&#xff0c;dispatcherServlet 是整个流程控制的中心&#xff0c;由它调用其它组件处理用户的请求&#xff0c;dispatcherServlet 的存在降低了组件之间的耦合性。 2.HandlerMappin…

poi解析word取参数方法${参数名}获取参数异常处理(2024-01-12)

poi 读取word模板&#xff0c;确保 ${参数名} 在一个XWPFRun XWPFDocument读取word模板&#xff0c;经常遇到 ${参数名} 没有被识别在一个XWPFRun中&#xff0c;导致参数解析异常如法实现参数替换。 这里只是介绍word模板参数解析问题&#xff0c;让word格式如何转换为可以正常…

Baumer工业相机堡盟工业相机如何通过NEOAPI SDK实现相机的高速图像保存(C#)

Baumer工业相机堡盟工业相机如何通过NEOAPI SDK实现相机的高速图像保存&#xff08;C#&#xff09;&#xff09; Baumer工业相机Baumer工业相机的图像高速保存的技术背景Baumer工业相机通过NEOAPI SDK函数图像高速保存在NEOAPI SDK里实现线程高速图像保存&#xff1a;工业相机高…

多输入多输出 | Matlab实现PSO-CNN粒子群优化卷积神经网络多输入多输出预测

多输入多输出 | Matlab实现PSO-CNN粒子群优化卷积神经网络多输入多输出预测 目录 多输入多输出 | Matlab实现PSO-CNN粒子群优化卷积神经网络多输入多输出预测预测效果基本介绍模型背景程序设计参考资料 预测效果 基本介绍 Matlab实现PSO-CNN粒子群优化卷积神经网络多输入多输出…

性能测试分析案例-使用动态追踪定位性能瓶颈

所谓动态追踪&#xff0c;就是在系统或者应用程序正常运行的时候&#xff0c;通过内核中提供的探针&#xff0c;来动态追踪它们的行为&#xff0c;从而辅助排查出性能问题的瓶颈。 使用动态追踪&#xff0c;可以在不修改代码、不重启服务的情况下&#xff0c;动态了解应用程序或…

《 乱弹篇(二)》

题记 昨&#xff08;2024年1月12日&#xff09;天&#xff0c;既然笔者因感到写时评文力不从心&#xff0c;新辟一专栏《乱弹篇》&#xff0c;开始了“ 东西南北&#xff0c;古今中外&#xff0c;谈而不乱&#xff0c;抒怀而已”的写作路径&#xff0c;就要走下去&#xff0c;…

debian12部署Gitea服务

首先安装git、wget、sqlite&#xff0c;然后进行用户和组的相关设置 sudo apt install -y git wget sqlite3 新增一个git用户与一个git组 sudo adduser --system --group --disabled-password --shell /bin/bash --home /home/git --gecos Git Version Control git 给git用户设…

必看!2023年机器人领域十大事件!

原创 | 文 BFT机器人 2023年&#xff0c;机器人产业快速发展&#xff0c;成就了机器人领域的一个又一个里程碑。机器人行业涌现了许多令人瞩目的事件&#xff0c;实现了重大突破&#xff0c;展示了机器人技术在各个领域的广泛应用和革命性变革。 本文将对2023年机器人领域的十…

数字化时代,VR全景展示如何让用户一窥全貌?

数字化时代&#xff0c;VR全景展示为各行各业提供了无限的可能性。随着VR全景技术的逐步普及&#xff0c;VR全景展示以其独特的呈现方式和新颖十足的交互体验&#xff0c;正在不断改变着人们对于展示宣传的理解。 传统的展示方式&#xff0c;通常需要将产品、图文、品牌等元素集…

131基于matlab的差分进化算法优化K均值聚类问题

基于matlab的差分进化算法优化K均值聚类问题&#xff0c;可调整K参数得到最佳聚类结果。输出聚类可视化图和优化迭代曲线。可替换自己的数据&#xff0c;程序已调通&#xff0c;可直接运行。 131matlab差分进化算法K均值聚类 (xiaohongshu.com)