牛客小白月赛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…

5374: 【数学】最后一击

题目描述 小爱和小艾两人组队打一只怪兽。一开始怪兽有 n 点生命值&#xff0c;当 n 变成 0 或更低时&#xff0c;怪兽就被消灭了。他们两人是同时开始攻击的&#xff0c;小爱每分钟可以攻击 a 下&#xff0c;小艾每分钟可以攻击 b 下。若 a2&#xff0c;b4&#xff0c;则小爱…

深圳市第六批专精特新“小巨人”企业申报和第三批专精特新“小巨人”企业申报开始了

各区&#xff08;新区、特别合作区&#xff09;相关工作部门&#xff0c;各企业&#xff1a; 根据《工业和信息化部办公厅关于开展第六批专精特新“小巨人”企业培育和第三批专精特新“小巨人”企业复核工作的通知》&#xff08;工信厅企业函〔2024〕142号&#xff09;要求&…

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

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

Phpstorm环境配置与应用

PhpStorm是一款功能强大的PHP集成开发环境&#xff0c;配置与应用涉及以下步骤&#xff1a; 下载与安装&#xff1a; 访问 PhpStorm 官网下载地址&#xff0c;选择合适的版本进行下载。双击下载的安装包文件进行安装&#xff0c;过程类似于其他IntelliJ IDEA产品。 个性化设…

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…

秋招嵌入式面经

24秋招-汇川嵌入式面经--超详细&#xff01; 一面 8月24日投递 9月3日一面&#xff08;30min&#xff09; 自我介绍&#xff1a; 介绍一下你的第一个项目吧 对于MCU的选型为什么使用F4的STM32&#xff1f; 项目里面用到了SPI进行两块MCU之间的通信&#xff0c;介绍一下SPI…

Linux操作系统配置git的ssh

系统&#xff1a;Ubuntu20.04LTS 安装git&#xff1a; sudo apt install git 配置git&#xff1a; # 添加全局git用户和邮箱 git config --global user.name "用户名" git config --global user.email "邮箱" # 查看用户名和邮箱是否有误 git config --li…

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…

【Python】用python实现编译脚本

这个脚本可以自动扫描目录下的.c和.s文件并编译&#xff0c;同时生成hex和bin文件 &#xff0c;可以代替Makefile工作。cortex-m 单片机 # -*- coding: gbk -*-import os import sys import time修改编译脚本之后需要全编译一次# CC gcc CC C:\\ARM_GCC\\bin\\arm-none-eabi-…

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

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

PHP中常见的@注释的含义

api: 提供给第三方使用的接口 author: 标明作者 param: 参数 return: 返回值 todo: 待办 version: 版本号 inheritdoc: 文档继承 property: 类属性 property-read: 只读属性 property-write: 只写属性 const: 常量 deprecated: 过期方法 example: 示例 final: 标识类是终态, 禁…

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

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

速看!2024年强基计划报考流程及常见问答

01什么是强基计划&#xff1f; 为加强基础学科拔尖创新人才选拔培养&#xff0c;教育部在深入调研、总结高校自主招生和上海等地高考综合改革试点经验的基础上&#xff0c;制定出台了《关于在部分高校开展基础学科招生改革试点工作的意见》&#xff08;也称“强基计划”&#…

SpringBoot启动加载自己的策略类到容器中使用?

使用InitializingBean接口 springboot中在启动的会自动把所有的实现同一个接口的类&#xff0c;都会转配到标注Autowired的list里面 而且实现了InitializingBean接口&#xff0c;在启动的赋值的时候&#xff0c;我们会把所有的策略类&#xff0c;重放到map中&#xff0c;我们在…

c++ 11 添加功能 变量类型推导

1.概要 变量类型推导 2.代码 #include <iostream> #include <map> using namespace std; int main() { std::map<std::string, std::string> m{ {"a", "apple"}, {"b","banana"} }; // 使用迭代器遍历…