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


前言

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


整体评价

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

第一场的比赛,感觉题目出的比较典,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做为除数比较特殊,它打破了字符串的顺序限制。


写在最后

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

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

springcloud sleuth分布式请求链路跟踪

简介 在微服务框架中&#xff0c;一个由客户端发起的请求在后端系统中会经过多个不同的的服务节点调用来协同产生最后的请求结果&#xff0c;每一个前段请求都会形成一条复杂的分布式服务调用链路&#xff0c;链路中的任何一环出现高延时或错误都会引起整个请求最后的失败. S…

【深度学习每日小知识】Logistic Loss 逻辑回归

逻辑回归的损失函数 线性回归的损失函数是平方损失。逻辑回归的损失函数是对数损失&#xff0c;定义如下&#xff1a; L o g L o s s ∑ ( x , y ) ∈ D − y log ⁡ ( y ′ ) − ( 1 − y ) log ⁡ ( 1 − y ′ ) LogLoss\sum_{(x,y)\in D}-y\log(y)-(1-y)\log(1-y) LogLoss…

黑马程序员——2022版软件测试——乞丐版——day02

目录&#xff1a; 解决穷举场景 等价类划分法案例&#xff08;qq合法验证&#xff09;案例&#xff08;城市电话验证&#xff09;总结&#xff08;应用场景&#xff09;解决边界限制问题 步骤案例1案例2总结解决多条件有依赖关系测试 介绍步骤案例&#xff08;订单&#xff09…

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

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

LLM主流框架:Causal Decoder、Prefix Decoder和Encoder-Decoder

本文将介绍如下内容&#xff1a; transformer中的mask机制Causal DecoderPrefix DecoderEncoder Decoder总结 一、transformer中的mask机制 在Transformer模型中&#xff0c;mask机制是一种用于在self-attention中的技术&#xff0c;用以控制不同token之间的注意力交互。具体…

Debezium发布历史64

原文地址&#xff1a; https://debezium.io/blog/2019/07/12/streaming-cassandra-at-wepay-part-1/ 欢迎关注留言&#xff0c;我是收集整理小能手&#xff0c;工具翻译&#xff0c;仅供参考&#xff0c;笔芯笔芯. 在 WePay 上流式传输 Cassandra - 第 1 部分 七月 12, 2019 …

HackTheBox - Medium - Linux - Faculty

Faculty Faculty 是一台中型 Linux 机器&#xff0c;具有 PHP Web 应用程序&#xff0c;该应用程序使用的库容易受到本地文件包含的影响。利用该库中的 LFi 会泄露一个密码&#xff0c;该密码可用于通过 SSH 以名为“gbyolo”的低级用户身份登录。用户“gbyolo”有权作为“dev…

Leetcode 剑指 Offer II 061. 查找和最小的 K 对数字

题目难度: 中等 原题链接 今天继续更新 Leetcode 的剑指 Offer&#xff08;专项突击版&#xff09;系列, 大家在公众号 算法精选 里回复 剑指offer2 就能看到该系列当前连载的所有文章了, 记得关注哦~ 题目描述 给定两个以升序排列的整数数组 nums1 和 nums2 , 以及一个整数 k…

【GNN2】PyG完成图分类任务,新手入门,保姆级教程

上次讲了如何给节点分类&#xff0c;这次我们来看如何用GNN完成图分类任务&#xff0c;也就是Graph-level的任务。 【GNN 1】PyG实现图神经网络&#xff0c;完成节点分类任务&#xff0c;人话、保姆级教程-CSDN博客 图分类就是以图为单位的分类&#xff0c;举个例子&#xff1…

服务器管理平台开发(3)- Web后端

Web服务端 整体架构采用前后端分离形式&#xff0c;后端使用Golang实现&#xff0c;参考Gin框架 1、后端服务 1.1、服务端架构 代码可参考Github开源项目&#xff1a;https://github.com/pbrong/hrms 1.2、服务地址 http://x.x.x.x:8000/api/v1/meta/info http://x.x.x.x:800…

算法第十七天-构造有效字符串的最少插入数

构造有效字符串的最少插入数 题目要求 解题思路 考虑abc的个数 假设答案有n个"abc"组成&#xff0c;那么需要插入的字符个数为 3 ∗ n − l e n ( s ) 3*n - len(s) 3∗n−len(s)。 对于相邻的两个字符x和y&#xff08;x在y左侧&#xff09;&#xff1a; 如果 x…

anaconda创建虚拟环境启动jupyter notebook

1.进入虚拟环境 &#xff08;以环境名为py37_pytorch1.9为例&#xff09; 创建虚拟环境: conda create -n py37_pytorch1.9 python3.7 查看已经创建的虚拟环境&#xff1a; ​​​​​​​conda env list 切换/进入环境&#xff1a; conda activate py37_pytorch1.9 删除环…

MathType绝对是我数学编辑的首选工具!

去年&#xff0c;微软曾说&#xff0c;要去掉Office里的公式编辑器&#xff0c;建议用户使用MathType编辑公式。目前Office用户可以到微软官网安装MathType的插件&#xff0c;现在免费使用&#xff0c;以后要收费。Word里安装这个插件以后&#xff0c;就会出现MathType的菜单。…

最好的 8 个解锁 Android 手机的应用程序分析

如何解锁我的 Android 手机是一个困扰全球数百万人的问题。有多种Android解锁器可用于解锁手机。用户应确保选择最好的应用程序以轻松满意地完成工作。必须注意的是&#xff0c;数据在解锁手机的整个过程中都是安全可靠的。此类应用程序还应该能够在所有情况下检索数据。 锁屏移…

论文阅读:Feature Refinement to Improve High Resolution Image Inpainting

项目地址&#xff1a;https://github.com/geomagical/lama-with-refiner 论文地址&#xff1a;https://arxiv.org/abs/2109.07161 发表时间&#xff1a;2022年6月29日 项目体验地址&#xff1a;https://colab.research.google.com/github/advimman/lama/blob/master/colab/LaMa…

设计模式之访问者模式【行为型模式】

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档> 学习的最大理由是想摆脱平庸&#xff0c;早一天就多一份人生的精彩&#xff1b;迟一天就多一天平庸的困扰。各位小伙伴&#xff0c;如果您&#xff1a; 想系统/深入学习某…

Redis重点总结补充

Redis重点总结 1.redis分布式锁 2.redission实现分布式锁 注意&#xff1a;加锁、设置过期时间等操作都是基于lua脚本完成. redisson分布式锁&#xff0c;实现可重入&#xff08;前提是同一个线程下 3.redis主从集群 实现主从复制 ( Master-slave Replication)的工作原理 : …

Vulnhub靶机:driftingblues 1

一、介绍 运行环境&#xff1a;Virtualbox 攻击机&#xff1a;kali&#xff08;10.0.2.15&#xff09; 靶机&#xff1a;driftingblues1&#xff08;10.0.2.17&#xff09; 目标&#xff1a;获取靶机root权限和flag 靶机下载地址&#xff1a;https://www.vulnhub.com/entr…

redis夯实之路-主从复制详解

Redis中可以通过执行slaveof命令或者设置slaveof选项&#xff0c;让一个服务器区复制另一个服务器&#xff0c;被复制的为主服务器&#xff0c;复制的为从服务器。 复制 Redis中可以通过执行slaveof命令或者设置slaveof选项&#xff0c;让一个服务器区复制另一个服务器&#…

实录分享 | 央企大数据平台架构发展趋势与应用场景的介绍

分享嘉宾&#xff1a; 孟子涵-中国华能集团信息中心平台架构师 2021年华能就与Alluxio建立了合作&#xff0c;共同写了整个华能统一纳管的架构方案。这个方案我认为是现在我们在央企里边比较核心的一套体系&#xff0c;能让全集团所有我们认为重要的数字化资源实现真正的统一集…