牛客周赛 Round 29 解题报告 | 珂学家 | 博弈概率DP

news2024/11/20 14:43:11

前言

alt


整体评价

F题真心好题,很典,学到了很多。D题用了对顶堆,写到一半就想到了更简单的方法,哭。E题是基于众数的构造。


欢迎关注

珂朵莉 牛客周赛专栏

珂朵莉 牛客小白月赛专栏


A. 小红大战小紫

思路: 模拟

n, m = list(map(int, input().split()))

if n > m:
    print("kou")
elif n < m:
    print("yukari")
else:
    print("draw")

B. 小红的白日梦

思路: 模拟

n = int(input())
day = input()
night = input()

res = 0
for i in range(n):
    if day[i] == 'Y' and night[i] == 'Y':
        res += 3
    elif day[i] == 'Y' and night[i] == 'N':
        res += 2
    elif day[i] == 'N' and night[i] == 'Y':
        res += 2

print(res)

C. 小红的小小红

思路: 贪心构造

先构造xiaohong, 后续字符按剩余数量追加即可

from collections import Counter

s = input()

cnt = Counter(s)

res = []
for c in "xiaohong":
    res.append(c)
    cnt[c] -= 1
    
for (k, v) in cnt.items():
    if v > 0:
        res.extend([k] * v)
    
print(''.join(res))

D. 小红的中位数

思路: 对顶堆

写复杂了,中间状态维护太麻烦了。

仅供负面教材典型。

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.PriorityQueue;
import java.util.StringTokenizer;
import java.util.TreeMap;
import java.util.stream.Collectors;

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

        // 对顶堆
        TreeMap<Integer, Integer> h1 = new TreeMap<>();
        TreeMap<Integer, Integer> h2 = new TreeMap<>();
        int cnt1 = 0, cnt2 = 0;

        for (int i = 0; i < n; i++) {
            if (cnt1 == cnt2) {
                h1.merge(arr[i], 1, Integer::sum);
                cnt1++;
            } else {
                h2.merge(arr[i], 1, Integer::sum);
                cnt2++;
            }

            if (cnt1 > 0 && cnt2 > 0 && h1.lastKey() > h2.firstKey()) {
                int k1 = h1.lastKey();
                int k2 = h2.firstKey();

                h1.computeIfPresent(k1, (a, b) -> b > 1 ? b - 1 : null);
                h2.computeIfPresent(k2, (a, b) -> b > 1 ? b - 1 : null);

                h1.merge(k2, 1, Integer::sum);
                h2.merge(k1, 1, Integer::sum);
            }
        }

        double[] f = new double[n];
        for (int i = 0; i < n; i++) {
            if (h1.containsKey(arr[i])) {
                h1.computeIfPresent(arr[i], (a, b)-> b > 1 ? b - 1 : null);
                cnt1--;
            } else {
                h2.computeIfPresent(arr[i], (a, b)-> b > 1 ? b - 1 : null);
                cnt2--;
            }
            if (cnt1 < cnt2) {
                int k2 = h2.firstKey();
                h2.computeIfPresent(k2, (a, b) -> b > 1 ? b - 1 : null);
                h1.merge(k2, 1, Integer::sum);
                cnt1++;
                cnt2--;
            } else if (cnt1 > cnt2 + 1) {
                int k1 = h1.lastKey();
                h1.computeIfPresent(k1, (a, b) -> b > 1 ? b - 1 : null);
                h2.merge(k1, 1, Integer::sum);
                cnt1--;
                cnt2++;
            }

            if (cnt1 > cnt2) {
                f[i] = h1.lastKey();
            } else {
                f[i] = (h1.lastKey() + h2.firstKey()) / 2.0;
            }

            if (cnt1 > cnt2) {
                h2.merge(arr[i], 1, Integer::sum);
                cnt2++;
            } else {
                h1.merge(arr[i], 1, Integer::sum);
                cnt1++;
            }

            while (cnt1 > 0 && cnt2 > 0 && h1.lastKey() > h2.firstKey()) {
                int k1 = h1.lastKey();
                int k2 = h2.firstKey();

                h1.computeIfPresent(k1, (a, b) -> b > 1 ? b - 1 : null);
                h2.computeIfPresent(k2, (a, b) -> b > 1 ? b - 1 : null);

                h1.merge(k2, 1, Integer::sum);
                h2.merge(k1, 1, Integer::sum);
            }
        }
        System.out.println(Arrays.stream(f).mapToObj(x -> String.format("%.1f", x)).collect(Collectors.joining("\n")));
    }

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

}

E. 小红构造数组

思路: 众数+构造

只要 众数 <=(m+1)/2, m为数组长度, 则一定可以构造

按频率(从大到小)优先填充偶数位(0-index),然后在填充奇数位,这样天然保证相同元素被隔离

可以反证,证明该思路,一定是OK的


import java.io.*;
import java.util.*;
import java.util.stream.Collectors;

public class Main {

    static List<long[]> split(long n) {
        List<long[]> res = new ArrayList<>();
        for (long i = 2; i <= n / i; i++) {
            if (n % i == 0) {
                int cnt = 0;
                while (n % i == 0) {
                    n /= i;
                    cnt++;
                }
                res.add(new long[] {i, cnt});
            }
        }
        if (n > 1) {
            res.add(new long[] {n, 1});
        }
        return res;
    }

    public static void main(String[] args) {
        Scanner sc = new Scanner(new BufferedInputStream(System.in));
        long e = sc.nextLong();
        if (e == 1) {
            System.out.println(-1);
            return;
        }
        
        List<long[]> primes = split(e);

        // 感觉像众数的构造
        int n = 0;
        Collections.sort(primes, Comparator.comparing(x -> -x[1]));
        int m = (int)primes.get(0)[1];
        for (long[] x: primes) {
            n += (int)x[1];
        }
        if (m > (n + 1) / 2) {
            System.out.println(-1);
        } else {
            Long[] res = new Long[n];
            int ptr = 0;
            for (long[] x: primes) {
                for (int j = 0; j < x[1]; j++) {
                    res[ptr] = x[0];
                    ptr += 2;
                    if (ptr >= n) ptr = 1;
                }
            }
            System.out.println(n);
            System.out.println(Arrays.stream(res).map(String::valueOf).collect(Collectors.joining(" ")));
        }
    }

}

F. 小红又战小紫

背景: 博弈+概率DP

思路: 状态压缩 + 博弈简化


因为和堆的位子无关,只和堆的石头数有关。

因此可以把很多堆(只有1和2),压缩为(1个石头的堆数,2个石头的堆数)

这样在博弈过程中,其状态就从n维(n<=1000)降维压缩到2维


博弈简化

博弈是套着 alpha+beta剪枝

但是这里面其实有策略挑选

  • 如果选用1技能,得到胜率概率为p1
  • 如果选用2技能,得到胜率概率为p2

取其 max(p1, p2)

因为概率取模会丢失大小关系,所以这边需要保留真实的概率值,这样就很麻烦。


这边有个特殊情况

就是当1,2个数得石头堆都存在时,如果选用技能2,那一定输,也就是胜率0

在这个前提下

博弈策略,只需要单独评估技能1就行(除只有1个石头堆的情况),这样就可以runtime过程中,使用模。


如果这题没有限制石头数目为1~2之间,那么这题得保留真实的概率,而不是模意义下的概率。


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.math.BigInteger;
import java.util.HashMap;
import java.util.Map;
import java.util.StringTokenizer;

public class Main {

    static long mod = (long)1e9 + 7;

    static int MZ = 1000;
    static long[] gFac = new long[MZ + 1];
    static long[] gInv = new long[MZ + 1];
    static {
        gFac[0] = 1;
        for (int i = 1; i <= MZ; i++) {
            gFac[i] = gFac[i-1] * i % mod;
        }
        gInv[MZ] = BigInteger.valueOf(gFac[MZ]).modInverse(BigInteger.valueOf(mod)).longValue();
        for (int i = MZ - 1; i >= 0; i--) {
            gInv[i] = gInv[i + 1] * (i + 1) % mod;
        }
    }

    static Map<Long, Long> memo = new HashMap<>();
    static long dfs(int x, int y) {
        // 直接使用技能2
        if (x > 0 && y == 0) {
            return 1;
        }
        // 必输态
        if (x == 0 && y == 0) {
            return 0;
        }

        long k = ((long)x << 32) | y;
        if (memo.containsKey(k)) {
            return memo.get(k);
        }

        long inv = gInv[x + y] * gFac[x + y - 1] % mod;

        // 策略1,随机堆
        long r = 0;
        if (x > 0) {
            long p = dfs(x - 1, y);
            r += (1 - p) * x % mod * inv % mod;
        }
        if (y > 0) {
            long p = dfs(x + 1, y - 1);
            r += (1 - p) * y % mod * inv % mod;
        }

        r = (r % mod + mod) % mod;
        memo.put(k, r);
        return r;
    }


    public static void main(String[] args) {
        AReader sc = new AReader();
        int x = 0, y = 0;
        int n = sc.nextInt();
        int[] arr = new int[n];
        for (int i = 0; i < n; i++) {
            arr[i] = sc.nextInt();
            if (arr[i] == 1) x++;
            else if (arr[i] == 2) y++;
        }
        long p = dfs(x, y);
        System.out.println(p);
    }

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

}

写在最后

alt

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

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

相关文章

Qt6入门教程 9:QWidget、QMainWindow和QDialog

目录 一.QWidget 1.窗口和控件 2.事件 二.QMainWindow 三.QDialog 1.模态对话框 1.1模态对话框 1.2.半模态对话框 2.非模态对话框 在用Qt Creator创建Qt Widgets项目时&#xff0c;会默认提供三种基类以供选择&#xff0c;它们分别是QWidget、QMainWIndow和QDialog&am…

ChatGPT五大教育潜能与四大教育风险

关于ChatGPT将对学校教育产生何种影响&#xff0c;教育界尚未达成共识。这在很大程度上反映了人们审视ChatGPT教育潜能时所采取的不同视角和立场。如果我们从前面提及的生态视角和学习者发展立场来看&#xff0c;ChatGPT可以与学习者之间建立协作、共生和进化的良性生态关系&am…

【Unity】AB包下载

【Unity】AB包下载 1.使用插件打AB包 a.AB包分类 一般地&#xff0c;将预制体作为AB包资源&#xff0c;不仅需要对预制体本身进行归类&#xff0c;还要对其涉及的动画&#xff08;AnimationClip&#xff09;、动画状态机&#xff08;AnimatorController&#xff09;、以及所…

7、机器学习中的数据泄露(Data Leakage)

找到并修复这个以微妙的方式破坏你的模型的问题。 数据泄露这个概念在kaggle算法竞赛中经常被提到,这个不同于我们通常说的生活中隐私数据暴露,而是在竞赛中经常出现某支队伍靠着对极个别feature的充分利用,立即将对手超越,成功霸占冠军位置,而且与第二名的差距远超第二名…

[足式机器人]Part2 Dr. CAN学习笔记- 最优控制Optimal Control Ch07-1最优控制问题与性能指标

本文仅供学习使用 本文参考&#xff1a; B站&#xff1a;DR_CAN Dr. CAN学习笔记 - 最优控制Optimal Control Ch07-1最优控制问题与性能指标

基于OpenSSL的SSL/TLS加密套件全解析

概述 SSL/TLS握手时&#xff0c;客户端与服务端协商加密套件是很重要的一个步骤&#xff0c;协商出加密套件后才能继续完成后续的握手和加密通信。而现在SSL/TLS协议通信的实现&#xff0c;基本都是通过OpenSSL开源库&#xff0c;本文章就主要介绍下加密套件的含义以及如何在O…

机器人制作开源方案 | 全自动导航分拣机器人

作者&#xff1a;孙国峰 董阳 张鑫源 单位&#xff1a;山东科技大学 机械电子工程学院 指导老师&#xff1a;张永超 贝广霞 1. 研究意义 1.1 研究背景 在工业生产中&#xff0c;机器人在解决企业的劳动力不足&#xff0c;提高企业劳动生产率&#xff0c;提高产品质量和降低…

【设计模式】适配器和桥接器模式有什么区别?

今天我探讨一下适配器模式和桥接模式&#xff0c;这两种模式往往容易被混淆&#xff0c;我们希望通过比较他们的区别和联系&#xff0c;能够让大家有更清晰的认识。 适配器模式&#xff1a;连接不兼容接口 当你有一个类的接口不兼容你的系统&#xff0c;而你又不希望修改这个…

【笔记】Blender4.0建模入门-3物体的基本操作

Blender入门 ——邵发 3.1 物体的移动 演示&#xff1a; 1、选中一个物体 2、选中移动工具 3、移动 - 沿坐标轴移动 - 在坐标平面内移动 - 自由移动&#xff08;不好控制&#xff09; 选中物体&#xff1a;右上的大纲窗口&#xff0c;点击物体名称&#xff0c;物体的轮…

【Python 元编程】装饰器入门指南

Python装饰器入门指南&#x1f680; 在编程世界中&#xff0c;效率和优雅的代码往往是我们所追求的目标。Python 作为一种强大且灵活的编程语言&#xff0c;提供了一个称为“装饰器”的功能&#xff0c;让我们能够以一种简洁和优雅的方式扩展和管理我们的代码。 本文旨在为初…

利用appium自动控制移动设备并提取数据

安装appium-python-client模块并启动已安装好的环境 安装appium-python-client模块 在window的虚拟环境下执行pip install appium-python-client 启动夜神模拟器&#xff0c;进入夜神模拟器所在的安装路径的bin目录下&#xff0c;进入cmd终端&#xff0c;使用adb命令建立adb…

生产环境 OpenFeign 的配置最佳实践

基础使用 OpenFeign 全方位讲解 1. 生产环境 OpenFeign 的配置事项 1.1 如何更改 OpenFeign 默认的负载均衡策略 warehouse-service: #服务提供者的微服务IDribbon:#设置对应的负载均衡类NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule1.2 开启默认的 O…

C++ //练习 2.14 下面的程序合法吗?如果合法,它将输出什么?

C Primer&#xff08;第5版&#xff09; 练习 2.14 练习 2.14 下面的程序合法吗&#xff1f;如果合法&#xff0c;它将输出什么&#xff1f; int i 100, sum 0; for(int i 0; i ! 10; i)sum i; std::cout<<i<<" "<<sum<<std::endl;环境…

scipy通过快速傅里叶变换实现滤波

文章目录 fft模块简介fft函数示例滤波 fft模块简介 scipy官网宣称&#xff0c;fftpack模块将不再更新&#xff0c;或许不久之后将被废弃&#xff0c;也就是说fft将是唯一的傅里叶变换模块。 Fourier变换极其逆变换在数学上的定义如下 F ( ω ) ∫ − ∞ ∞ f ( t ) e − i ω…

Python图像处理【19】基于霍夫变换的目标检测

基于霍夫变换的目标检测 0. 前言1. 使用圆形霍夫变换统计图像中圆形对象2. 使用渐进概率霍夫变换检测直线2.1 渐进霍夫变换原理2.2 直线检测 3. 使用广义霍夫变换检测任意形状的对象3.1 广义霍夫变换原理3.2 检测自定义形状 小结系列链接 0. 前言 霍夫变换 (Hough Transform,…

2024最新:optee系统开发精讲 - 课程介绍

&#xff08;本课程中如有涉及代码或硬件架构&#xff0c;则对应的版本号&#xff1a;TF-A 2.80&#xff0c;optee 3.20, Linux Kernel 6.3&#xff0c;armv8.79.0的aarch64&#xff09; &#xff08;注意&#xff1a; 该课程没有PPT&#xff0c;该课程是对照代码讲解的&#x…

回归预测 | Matlab基于ABC-SVR人工蜂群算法优化支持向量机的数据多输入单输出回归预测

回归预测 | Matlab基于ABC-SVR人工蜂群算法优化支持向量机的数据多输入单输出回归预测 目录 回归预测 | Matlab基于ABC-SVR人工蜂群算法优化支持向量机的数据多输入单输出回归预测预测效果基本描述程序设计参考资料 预测效果 基本描述 1.Matlab基于ABC-SVR人工蜂群算法优化支持…

矩阵重叠问题判断

创作背景 看到一道题目有感而发想写一篇题解&#xff0c;涉及的是一种逆向思维 桌面窗体重叠 - 洛谷https://www.luogu.com.cn/problem/U399827题目来源于《信息学奥赛课课通》 大致就是给一个长方形的左上顶点坐标&#xff08;x1,y1&#xff09;和右下顶点坐标&#xff08;x…

面试题:SpringBoot项目怎么设计业务操作日志功能?

文章目录 前言需求描述与分析系统日志操作日志 设计思路Spring AOPFilter和HandlerInterceptorSpringAOP、过滤器、拦截器对比 实现方案环境配置依赖配置表结构设计代码实现 测试调试方法验证结果 总结 前言 很久以前都想写这篇文章&#xff0c;一直没有空&#xff0c;但直到现…

【QT+QGIS跨平台编译】之一:【sqlite+Qt跨平台编译】(一套代码、一套框架,跨平台编译)

文章目录 一、sqlite3介绍二、文件下载三、文件分析四、pro文件五、编译实践 一、sqlite3介绍 SQLite是一款轻型的数据库&#xff0c;是遵守ACID的关系型数据库管理系统&#xff0c;它包含在一个相对小的C库中。它是D.RichardHipp建立的公有领域项目。它的设计目标是嵌入式的&…