牛客小白月赛90(A,B,C,D,E,F)

比赛链接

官方题解(视频)

这场偏思维,感觉好像没啥算法。E需要动态维护前 k k k 小,F是个离散化加dp,状态和递推方程比较 非常规,建议还是看一下涨涨姿势。


A 小A的文化节

思路:

签到

code:

#include <iostream>
#include <cstdio>
using namespace std;
const int maxn=105;int n,m,a[maxn];int main(){cin>>n>>m;for(int i=1;i<=n;i++)cin>>a[i];int ans=0;for(int i=1,t;i<=m;i++){cin>>t;ans+=a[t];}cout<<ans;return 0;
}

B 小A的游戏

思路:

只有两种加分方式,一种是一个人加 3 3 3 分,另一个人加 0 0 0 分,一种是两人各加 1 1 1 分.。

发现如果没有平局的话,两人分数一定是 3 3 3 的倍数,加入平局后,两人分数的差值仍然是 3 3 3 的倍数。反过来,如果分数的差值是 3 3 3 的倍数的话,就可以凑出来某人赢了几场,平了几场,输了几场。换句话说,就是两人分数之差为 3 3 3 的倍数=有解。

code:

#include <iostream>
#include <cstdio>
using namespace std;int T,a,b;int main(){cin>>T;while(T--){cin>>a>>b;puts((abs(a-b)%3==0)?"Yes":"No");}return 0;
}

C 小A的数字

思路:

看半天以为是二进制位,结果是十进制位。。。

当然是尝试贪心地将每个数位都置为 0 0 0,如果本来就是 0 0 0 就置为 1 1 1。因为要求是正整数,所以结果为 0 0 0 的时候还需要特判。

code:

#include <iostream>
#include <cstdio>
#include <stack>
using namespace std;int T,n;int main(){cin>>T;while(T--){cin>>n;int flag=n%10;stack<int> s;while(n){s.push((n%10)?0:1);n/=10;}while(!s.empty() && s.top()==0)s.pop();if(s.empty()){if(flag==1)s.push(2);else s.push(1);}while(!s.empty()){cout<<s.top();s.pop();}cout<<endl;}return 0;
}

D 小A的线段(easy version)

思路:

因为 m ≤ 10 m\le 10 m10 很小,所以直接暴力枚举选取线段的情况,然后逐一验证即可。

验证的时候可以用差分来优化。

code:

#include <iostream>
#include <cstdio>
#include <vector>
using namespace std;
const int maxn=15;int n,m;
int st[maxn],ed[maxn];bool check(int sta){vector<int> a(n+5);for(int i=0;i<m;i++){if(sta>>i&1){a[st[i]]++;a[ed[i]+1]--;}}for(int i=1;i<=n;i++){a[i]+=a[i-1];if(a[i]<2)return false;}return true;
}int main(){cin>>n>>m;for(int i=0;i<m;i++)cin>>st[i]>>ed[i];int ans=0;for(int i=0;i<(1<<m);i++)ans+=check(i);cout<<ans;return 0;
}

E 小A的任务

思路:

因为我们选了所有前 i i i A A A 任务,才有资格去前 i i i B B B 任务中选任务,一开始的想法是 d p dp dp。第 i i i 个任务我们可以只选一个 A A A 任务,或者同时选择一个 A A A 任务和相应的 B B B 任务,设 d p [ i ] [ j ] dp[i][j] dp[i][j] 表示前 i i i 个任务选 j j j B B B 任务的最小时间,转移方程为 d p [ i ] [ j ] = m i n { d p [ i − 1 ] [ j ] , d p [ i − 1 ] [ j − 1 ] + B i } + A i dp[i][j]=min\{dp[i-1][j],dp[i-1][j-1]+B_i\}+A_i dp[i][j]=min{dp[i1][j],dp[i1][j1]+Bi}+Ai。不过这样转移时间复杂度是 O ( n 2 ) O(n^2) O(n2) 的,因为它会同时处理出前 i i i 个任务中选择 0 ∼ i 0\sim i 0i B B B 任务的最小代价,因此时间复杂度降不下来,大部分数据我们根本用不到。

考虑其他做法,发现如果我们决定只做前 i i i A A A 任务后,我们做 k k k B B B 任务一定是做前 i i i 个中用时最小的 k k k 个任务。这么做的好处是我们可以使用一个堆来动态维护住前 i i i B B B 任务中最小的 k k k 个用时,这样我们跑一遍下来就得到了 i i i k ∼ n k\sim n kn 所有情况下 B B B 任务的选取情况,也就得到了最小的用时。验证一遍的时间复杂度是 O ( n ∗ l o g k ) O(n*logk) O(nlogk) 的,总时间复杂度应该是 O ( n ∗ q ∗ l o g k ) O(n*q*logk) O(nqlogk),运算次数约为 1 0 5 ∗ 100 ∗ l o g ≈ 2 ∗ 1 0 8 10^5*100*log\approx2*10^8 105100log2108,时限有 3 s 3s 3s ,可以通过。

code:

#include <iostream>
#include <cstdio>
#include <queue>
using namespace std;
typedef long long ll;
const int maxn=1e5+5;int n,q;
int a[maxn],b[maxn];ll solve(int k){ll tot=0,ans;priority_queue<int> h;for(int i=1;i<=k;i++){tot+=a[i];tot+=b[i];h.push(b[i]);}ans=tot;for(int i=k+1;i<=n;i++){tot+=a[i];if(b[i]<h.top()){tot-=h.top();h.pop();tot+=b[i];h.push(b[i]);ans=min(ans,tot);}}return ans;
}int main(){cin.tie(0)->sync_with_stdio(false);cin>>n>>q;for(int i=1;i<=n;i++)cin>>a[i];for(int i=1;i<=n;i++)cin>>b[i];while(q--){int k;cin>>k;cout<<solve(k)<<endl;}return 0;
}

F 小A的线段(hard version)

思路:

不难发现其实区间里很多位置其实都是没啥用的。 1 0 5 10^5 105 个位置被 200 200 200 个线段分成了 400 400 400 多个段,段内的所有位置其实没啥用,我们其实可以直接把这些段看成一个点,一个位置。这样离散化一下, 1 0 5 10^5 105 个位置就变成了 400 400 400 多个位置。

因为每个位置只要覆盖两次及以上就行了,所以每个位置我们可以看作只有三种状态:覆盖了零次,覆盖了一次,覆盖两次以上,每条线段可以将若干位置的状态进行变化,因此考虑动态规划。

d p [ i ] [ j ] dp[i][j] dp[i][j] 表示前 i i i 个位置覆盖了两次及以上,前 j j j 个位置覆盖了一次的选取线段方法数,为了前面状态不会出现断层(比如前面先覆盖了两次,然后后面变成覆盖一次,然后又变成覆盖了两次),我们对所有线段按左端点进行排序,然后按顺序取更新 d p dp dp 值即可(因为我们考虑了左端点在前 i i i 个位置的线段,那么前面的位置就必须都是覆盖了两次,否则后面更新 d p dp dp 也不可能更新状态,这样就保证了我们不需要考虑前面出现断层的情况,因为一定更新不了答案)。

官方题解给出的状态转移方程如下:
在这里插入图片描述
我写的时候没看题解,直接分类讨论的,思路是一样的。转移方程如下:

假设我们现在考虑到了第 k k k 个线段,线段左右端点分别为 l , r l,r l,r,设 d p [ i ] [ j ] dp[i][j] dp[i][j] 表示前 i i i 个位置覆盖了两次及以上,前 j j j 个位置覆盖了一次的选取线段方法数 ( l ≤ r , i ≤ j ) (l\le r,i\le j) (lr,ij)。于是有(箭头表示可以转移):

  1. 不选取该线段: d p [ k − 1 ] [ i ] [ j ] → d p [ k ] [ i ] [ j ] dp[k-1][i][j]\rightarrow dp[k][i][j] dp[k1][i][j]dp[k][i][j]
  2. 选取该线段:
    1. l − 1 ≤ i ≤ j ≤ r l-1\le i\le j\le r l1ijr 时, d p [ k − 1 ] [ i ] [ j ] → d p [ k ] [ j ] [ r ] dp[k-1][i][j]\rightarrow dp[k][j][r] dp[k1][i][j]dp[k][j][r]
    2. l − 1 ≤ i ≤ r < j l-1\le i\le r\lt j l1ir<j 时, d p [ k − 1 ] [ i ] [ j ] → d p [ k ] [ r ] [ j ] dp[k-1][i][j]\rightarrow dp[k][r][j] dp[k1][i][j]dp[k][r][j]
    3. r < i ≤ j r\lt i\le j r<ij 时, d p [ k − 1 ] [ i ] [ j ] → d p [ k ] [ i ] [ j ] dp[k-1][i][j]\rightarrow dp[k][i][j] dp[k1][i][j]dp[k][i][j]

上面第四条和第一条的实际意义是不一样的,前者表示不选取该线段的方法数,后者是选取的方法数,所以两者不影响,正常相加即可。

根据递推式,发现我们实际用的其实是 l − 1 l-1 l1,而不是 l l l,因为离散化后点与点之间相邻关系会被打破,比如 3 , 7 3,7 3,7 离散化后是 1 , 2 1,2 1,2,虽然离散化后 2 2 2 减一就等于 1 1 1,但这并不代表 7 7 7 减一就等于 3 3 3,所以我们离散化的时候直接对 l − 1 l-1 l1 离散化,而不是 l l l

另外就是 1 1 1 n n n 作为区间左右端点也要放入到离散化数组中去,左端点由于上面所有线段左端点都减一的影响,这里也要减 1 1 1,也就是说认为左端点是 0 0 0

code:

还能滚动数组优化,不过没写

#include <iostream>
#include <cstdio>
#include <vector>
#include <algorithm>
#define pii pair<int,int>
using namespace std;
typedef long long ll;
const int maxn=1e5+5;
const int maxm=205;
const ll mod=998244353;int n,m;
vector<pii> itv;vector<int> tmp;int main(){cin>>n>>m;tmp.push_back(0);tmp.push_back(n);for(int i=1,l,r;i<=m;i++){cin>>l>>r;l--;tmp.push_back(l);tmp.push_back(r);itv.push_back(pii(l,r));}sort(tmp.begin(),tmp.end());tmp.erase(unique(tmp.begin(),tmp.end()),tmp.end());n=tmp.size();auto find=[&](int x)->int{return lower_bound(tmp.begin(),tmp.end(),x)-tmp.begin()+1;};for(auto& [l,r]:itv){l=find(l);r=find(r);}sort(itv.begin(),itv.end());vector<vector<vector<ll> > > dp(m+1,vector<vector<ll> >(n+1,vector<ll>(n+1,0)));dp[0][1][1]=1;for(int k=1;k<=m;k++){auto [l,r]=itv[k-1];for(int i=0;i<=n;i++)for(int j=i;j<=n;j++)dp[k][i][j]=dp[k-1][i][j];for(int i=0;i<=n;i++){for(int j=i;j<=n;j++){if(l<=i){if(i<=r){if(j<=r){dp[k][j][r]+=dp[k-1][i][j];dp[k][j][r]%=mod;}else {dp[k][r][j]+=dp[k-1][i][j];dp[k][r][j]%=mod;}}else {dp[k][i][j]+=dp[k-1][i][j];dp[k][i][j]%=mod;}}}}}cout<<dp[m][n][n]<<endl;return 0;
}

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

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

相关文章

hive使用sqoop与oracle传输数据

下载地址 http://archive.apache.org/dist/sqoop 两个版本sqoop1&#xff08;1.4.x&#xff09;和sqoop2&#xff08;1.99.x&#xff09;&#xff0c;两种不同的架构。 本文使用sqoop1。 sqoop是apache旗下一款“hadoop与关系数据库之间传送数据”的工具。 导入数据&#xf…

中仕公考:2024年广东省高校毕业生‘三支一扶‘公告

2024年广东省三支一扶共计划招募3000名左右高校毕业生&#xff0c;服务期限为两年&#xff0c;具体招募岗位和条件可通过广东人事考试网查询。 招考条件&#xff1a; 年龄不超过30周岁(1993年4月22日后出生); 支教岗位须是已取得教师资格证的高校毕业生&#xff0c;支医专业…

C++ | Leetcode C++题解之第23题合并K个升序链表

题目: 题解&#xff1a; class Solution {// 21. 合并两个有序链表ListNode *mergeTwoLists(ListNode *list1, ListNode *list2) {auto dummy new ListNode(); // 用哨兵节点简化代码逻辑auto cur dummy; // cur 指向新链表的末尾while (list1 && list2) {if (list1…

JavaEE初阶Day 13:多线程(11)

目录 Day 13&#xff1a;多线程&#xff08;11&#xff09;常见的锁策略1. 悲观锁 vs 乐观锁2. 重量级锁 vs 轻量级锁3. 自旋锁 vs 挂起等待锁4. 可重入锁 vs 不可重入锁5. 公平锁 vs 非公平锁6. 互斥锁 vs 读写锁 synchronized实现原理1. 锁升级2. 锁消除3. 锁粗化 CAS Day 13…

自助棋牌室如何用一招留住80%的客户?

棋牌室如何用一招守住80%的回头客&#xff0c;你想知道吗&#xff1f; 记得收藏&#xff0c;希望对你有一点点帮助&#xff01; 今天我就分享一个非常简单的方法&#xff0c;简单到所有的棋牌室老板你立马就可以去执行的方法&#xff01;第一步&#xff0c;加好友&#xff0c;…

Java面试八股之Iterator接口和Iterable接口

1. Java为什么不直接实现Iterator接口&#xff0c;而是实现Iterable? 这道题算是一道比较基础的题&#xff0c;面试官肯定也不是想让回答得多深入&#xff0c;只是考查对迭代器的了解程度&#xff0c;最好是看过源码&#xff0c;实际上迭代器的源码并不难。我们把注释折叠起来…

LIUNX文件系统

目录 1.磁盘的物理结构 2.CHS定位法 3.磁盘的逻辑存储 4.系统层面 inode.block[15] 创建文件的流程 查找文件的流程 了解文件系统&#xff0c;首先要了解磁盘是如何存储和读取数据的。 1.磁盘的物理结构 可以理解这个盘上有很多的小磁铁&#xff0c;通过旋转盘面和摆动…

葡韵饼店:云上清明节,千里寄哀思

清明&#xff0c;又称踏青节、祭祖节、行清节&#xff0c;节期在仲春与暮春之交&#xff0c;源自于上古时代的祖先信仰和春祭礼俗&#xff0c;兼具人文与自然两大内涵。 每当到了这个时候&#xff0c;人们都会携带祭祀物品&#xff0c;与家人们齐聚结伴&#xff0c;登山祭祖&am…

支付宝支付之SpringBoot整合支付宝创建自定义支付二维码

文章目录 自定义支付二维码pom.xmlapplication.yml自定义二维码类AlipayService.javaAlipayServiceImpl.javaAlipayController.javaqrCode.html 自定义支付二维码 继&#xff1a;SpringBoot支付入门 pom.xml <dependency><groupId>org.springframework.boot<…

前端开发该不该“跳槽”到鸿蒙?

前言 面对互联网行业的激烈竞争&#xff0c;许多人都深感2023年已是不易&#xff0c;而展望2024年&#xff0c;似乎更是难上加难。这一切的根源&#xff0c;皆因行业多年发展后&#xff0c;人才市场的饱和现象愈发严重。那么&#xff0c;作为前端开发者&#xff0c;我们究竟该…

【尚硅谷】Git与GitLab的企业实战 学习笔记

目录 第1章 Git概述 1. 何为版本控制 2. 为什么需要版本控制 3. 版本控制工具 4. Git简史 5. Git工作机制 6. Git和代码托管中心 第2章 Git安装 第3章 Git常用命令 1. 设置用户签名 1.1 基本语法 1.2 案例实操 2. 初始化本地库 2.1 基本语法 2.2 案例实操 3. 查…

【运输层】TCP 的流量控制和拥塞控制

目录 1、流量控制 2、TCP 的拥塞控制 &#xff08;1&#xff09;拥塞控制的原理 &#xff08;2&#xff09;拥塞控制的具体方法 1、流量控制 一般说来&#xff0c;我们总是希望数据传输得更快一些。但如果发送方把数据发送得过快&#xff0c;接收方就可能来不及接收&#x…

Ubuntu 22.04 配置VirtualBox安装Windows 10虚拟机

Ubuntu 22.04 配置VirtualBox安装Windows 10虚拟机 文章目录 Ubuntu 22.04 配置VirtualBox安装Windows 10虚拟机1.安装virtualbox2.下载Window.iso文件并载入3.问题解决3.1 Kernel driver not installed (rc-1908)3.2 VT-x is disabled in the BIOS for all CPU modes 4.安装Wi…

带你实现一个github注册页面的星空顶

带你实现一个github注册页面的星空顶 github的注册页面可以说是非常的好看&#xff0c;如果没有看过的可以看下面的图片&#xff1a; 那么要如何实现下面的这个效果呢&#xff1f; 首先我们研究一下他的这个官网 首先我看到的后面的这个背景&#xff0c;是不是一个纯色的背景…

Linux安装Docker完整教程及配置阿里云镜像源

官网文档地址 安装方法 1、查看服务器内核版本 Docker要求CentOS系统的内核版本高于3.10 uname -r #通过 uname -r 命令查看你当前的内核版本2、首先卸载已安装的Docker&#xff08;如果有&#xff09; 2.1 确保yum包更新到最新 yum update2.2 清除原有的docker&#xff0c…

02_Fixture定位,Caliper卡尺工具,几何学工具

Fixture定位工具 需求: 测量工件的尺寸 使用Caliper(卡尺)工具 这个时候需要借助Fixture工具 VisionPro中的图像空间 “” 图像的当前空间&#xff0c;即CogImage中的“SelectedSpaceName”表示的名字空间 “#” 像素空间&#xff0c;即坐标原点为图片左上角的坐标空间&am…

TCP/IP协议—MQTT

TCP/IP协议—MQTT MQTT协议MQTT协议特点MQTT通信流程MQTT协议概念 MQTT报文固定报头可变报头有效载荷 MQTT协议 消息队列遥测传输&#xff08;Message Queuing Telemetry Transport&#xff0c;MQTT&#xff09;是一个基于客户端-服务器的消息发布/订阅传输协议。它的设计思想…

windows上安装make

下载地址 https://sourceforge.net/projects/gnuwin32/ 点击框中的下载&#xff0c;下载后安装。把安装路径添加到环境变量 PATH 中. 打开cmd&#xff0c;验证是否生效 安装包下载地址&#xff1a; https://download.csdn.net/download/qq_36314864/89163210

python读取DBF数据

DBF文件通常是由数据库软件&#xff08;如FoxPro或dBASE&#xff09;创建的数据库文件。Python中并没有直接读取DBF文件的内置库&#xff0c;但你可以使用第三方库如dbfread来读取DBF文件。 首先&#xff0c;你需要安装dbfread库。你可以使用pip来安装&#xff1a; pip insta…

【人工智能书籍分享】从ChatGPT到AIGC:人工智能重塑千行百业

今天又来给大家推荐一本人工智能方面的书籍<从ChatGPT到AIGC&#xff1a;人工智能重塑千行百业>。本书介绍了ChatGPT的前世今生&#xff0c;重点聚焦普通人如何使用ChatGPT获得工作和生活效率的提升&#xff0c;各行各业如何通过ChatGPT来改变自己的赛道状态。 使用Chat…