2023 广东省大学生程序设计竞赛(部分题解)

目录

A - Programming Contest

B - Base Station Construction

C - Trading

D - New Houses

E - New but Nostalgic Problem

I - Path Planning

K - Peg Solitaire

A - Programming Contest

签到题:直接模拟

直接按照题目意思模拟即可,为了好去重,我们使用set即可

void solve(){
   
    int l,r; cin>>l>>n;
    set<int> s;
    while(n--){
    	int x; cin>>x;
    	s.insert(x);
    }
    cin>>r;
    int ans = 0;
    for(int i=l;i<=r;i++) ans += !s.count(i);
    
    cout << ans << endl;
    
    return ;
}

B - Base Station Construction

 银牌题:优先队列优化dp

我们可以读懂题目也就是说对于一个区间[l,r]而言我们一定要选一个,可以知道r+1从l转移过来肯定是最优的,由此我们可以对于每一个点维护最优的前一个点的转移,同时注意到后缀一定是满足前缀的要求的所以pre[r+1]=max(pre[r+1],l)同时再用前缀最大值处理一下,我们定义在第i个点建立电站同时满足前面的每一个区间的同时的最优解为f_i,转移方程为f_i = min_{f_j} + a[i],为前缀的点同时随着i的增大j一定是同时增大的变化,所以可以考虑使用优先队列维护dp即可,同时注意怎么判断最后答案是上面,我们可以++n这样满足答案就是f_n

void solve(){
   
   
   	cin>>n;
   	vector<int> a(n+5),pre(n+5),q(n+5);
   	vector<LL> dp(n+5);
   	for(int i=1;i<=n;i++) cin>>a[i];
   	n++;
   	cin>>m;
   	while(m--){
   		int l,r; cin>>l>>r;
   		pre[r+1]=max(pre[r+1],l);
   	}
   	
   	for(int i=1;i<=n;i++) pre[i]=max(pre[i-1],pre[i]);
   	
   	int hh=0,tt=0;
   	q[0]=0;
   	for(int i=1;i<=n;i++){
   		while(hh<=tt and q[hh]<pre[i]) hh++;
   		dp[i] = dp[q[hh]] + a[i];
   		while(hh<=tt and dp[q[tt]]>=dp[i]) tt--; 
   		q[++tt]=i;
   	}
   	cout << dp[n] << endl;
    return ;
}

C - Trading

 签到题:贪心

我们可以有个明显的结论就是从价格最便宜的买入,在贵的卖出就行了,进一步贪心我肯定是买最多的同时卖了最优,所以就是买一半卖一半即可

void solve(){
    
    cin>>n;
    LL sum = 0;
    for(int i=1;i<=n;i++){
    	int a,b; cin>>a>>b;
    	w[i]={a,b};
    	sum += b;
    }
    sort(w+1,w+1+n);
	
	LL buy = 0,cnt = 0;
	for(int i=1;i<=n;i++){
		auto [a,b]=w[i];
		int now = min(sum/2-cnt,b);
		buy += (LL)a*now;
		cnt += now;
	}
	LL use = 0,num = 0;
	for(int i=n;i>=1;i--){
		auto [a,b]=w[i];
		int now = min(sum/2-num,b);
		use += (LL)a*now;
		num += now;
	}
	LL ans = use - buy;
    cout << ans << endl;
    return ;
}

D - New Houses

签到题:贪心

设有邻居贡献为x,无为y

我们有个明显的结论就是如果你是有邻居优就让你有邻居,否则让你没邻居,我们一开始可以所有人挤在一起,放置在前i个位置,\sum_i^nx_i,(特判n==1)接着按照没有邻居贡献大的来排序,可以注意到多了几个位置就可以有多少人是可以没有邻居的同时贡献要大于有邻居的时候才考虑,贡献为y-x,同时注意到如果说后面排了n-1个人的时候前面最开始就没有邻居了,就需要特判到底是合在一起还是分开贡献最优即可

void solve(){
   
    cin>>n>>m;
    LL ans = 0;
    // 一开始所有人都挤在一起
    for(int i=1;i<=n;i++){
    	int x,y; cin>>x>>y;
    	a[i]={x,y};
    	ans += x;
    }
    if(n==1){
    	cout << a[1].second << endl;
    	return ;
    }
    sort(a+1,a+1+n,[](PII a,PII b){return a.second-a.first>b.second-b.first;});
    
    int pos = 0;
    for(int i=1;i<=m-n and a[i].second-a[i].first>=0 and i<=n;i++){
    	auto [x,y]=a[i];
    	ans += y-x;
    	pos = i;
    }
    if(pos==n-1){// 由于前面挤在一起的只有一个人 考虑合在一起或者是分开
    	ans = max(ans+a[n-1].first-a[n-1].second,ans-a[n].first+a[n].second);
    }
    cout << ans << endl;
    return ;
}

E - New but Nostalgic Problem

 银牌-金牌题:trie树+dfs贪心

我们选出m个使得结果最小我们可以发现要维护的是最长公共前缀,那么我们考虑字符的存储可以考虑使用trie树,我们有一个贪心的想法,我一定是从aaa...abc....这样的结果来看是不是满足数量最优的,如果说对于当前已经选了“abc"下一个是选择d组合为abcd,那么满足是abcd的前缀起码要选择两个,同时前面的abc[a-c]肯定是都得加上因为如果这前面有更优解肯定跑到前面去了,同时对于[e-z]每一个分支最多选择一个,因为如果选择多了当前结果就不是abcd了,同时我们可以发现这样也就是遍历了每一个字符串而已,所以时间是\sum_{}s_i符合要求,接下来就是用实现即可

int tr[N][26],sum[N],ed[N];
string s,ans;
bool ok;
void insert(){
	int p = 0;
	for(auto&v:s){
		int x=v-'a';
		if(!tr[p][x]) tr[p][x]=++idx;
		p = tr[p][x];
		sum[p]++;
	}
	ed[p]++;
}
void used(){
	for(int i=0;i<=idx;i++){
		for(int j=0;j<26;j++) tr[i][j]=0;
		sum[i]=ed[i]=0;
	}
	ok = false;
	idx = 0;
	ans.clear();
}
void dfs(int u,int last){
	if(ok) return ;
	int s = 0;
	//ab 之后  aba abb abc abd ...
	//得到的答案是ab
	int now = last + ed[u];
	for(auto v : tr[u]) s += min(1,v); // 表示对于当前分支接着都取不一样
	
	if(now + s>=m){
		cout << (u ? ans : "EMPTY") << endl;
		ok = true;
		return ;
	}
	int pre = 0;
	for(int i=0;i<26;i++){
		if(!tr[u][i]) continue;
		// 表示需要加一个分支去走
		ans.push_back(i+'a');
		dfs(tr[u][i],now+pre+s-1); // 表示在s取过了
		ans.pop_back();
		pre += sum[tr[u][i]]-1; // 表示这个字母在s取过了
	}
}
void solve(){

    cin>>n>>m;
    for(int i=1;i<=n;i++){
    	cin>>s;
    	insert();
    }
    dfs(0,0);
    used();
    return ;
}

F - Traveling in Cells

金牌题:二分+动态开点线段树+树装数组

我们有个明显的想法就是对于操作3二分找到最远左右边界即可,但是对于左右边界如果判断是不是符合集合的值难以解决,我们可以注意到 颜色的数量过多,同时还得支持颜色的修改,我们考虑使用动态开点线段树来维护,对于每一个点开出的线段树的用到的节点数量只有(n+m)logn个,我们使用这个数据结构可以维护要求,同时对于查询左右区间的贡献已经修改值都可以通过树装数组来维护,核心还是考察了动态开点线段树

int t,n,m,k,idx;
struct code{
	int l,r;
	int val;
}tr[N*40];

int c[N],v[N],s[M];
int rc[N];
LL vc[N];

void update(int p){
	tr[p].val = tr[tr[p].l].val + tr[tr[p].r].val;
}

void change(int &p,int l,int r,int x,int val){
	if(!p) p = ++ idx;
	if(l==r){
		tr[p].val+=val;
		return ;
	}
	int mid = l+r>>1;
	if(x<=mid) change(tr[p].l,l,mid,x,val);
	else change(tr[p].r,mid+1,r,x,val);
	update(p);
}

int query(int p,int l,int r,int L,int R){
	if(!p) return 0;
	if(L <= l and r <= R) return tr[p].val;
	int mid = l+r>>1;
	int res = 0;
	if(L<=mid) res += query(tr[p].l,l,mid,L,R);
	if(R>mid)  res += query(tr[p].r,mid+1,r,L,R);
	return res;
}
void add(int k,int x){
	for(int i=k;i<=n;i+=lowbit(i)) vc[i] += x;
}
LL ask(int k){
	LL res = 0;
	for(int i=k;i;i-=lowbit(i)) res += vc[i];
	return res;
}
bool check(int l,int r){
	int cnt = 0;
	for(int i=1;i<=k;i++)
		cnt += query(rc[s[i]],1,n,l,r);
	return cnt == r-l+1;
}
void clear(){
	for(int i=1;i<=n;i++) rc[i]=vc[i]=0;
	for(int i=1;i<=idx;i++) tr[i].l=tr[i].r=tr[i].val=0;
	idx = 0;
}
void solve(){
    clear();
    cin>>n>>m;
    for(int i=1;i<=n;i++){
    	cin>>c[i];
    	change(rc[c[i]],1,n,i,1);
    }
    for(int i=1;i<=n;i++){
    	cin>>v[i];
    	add(i,v[i]);
    }
    while(m--){
    	int op,p,x;
    	cin>>op;
    	if(op==1){
    		cin>>p>>x;
    		change(rc[c[p]],1,n,p,-1);
    		change(rc[x],1,n,p,1);
    		c[p]=x;
    	}
    	else if(op==2){
    		cin>>p>>x;
    		add(p,x-v[p]);
    		v[p]=x;
    	}
    	else{
    		int pos;
    		cin>>pos>>k;
    		for(int i=1;i<=k;i++) cin>>s[i];
    		LL ans = 0;
    		int posl = pos,posr = pos;
    		int l = 1, r = pos;
    		while(l<r){
    			int mid = l+r>>1;
    			if(check(mid,pos)) r=mid;
    			else l=mid+1; 
    		}
    		posl = l;
    		l = pos,r = n;
    		while(l<r){
    			int mid=l+r+1>>1;
    			if(check(pos,mid)) l=mid;
    			else r=mid-1;
    		}
    		posr = r;
    		cout << ask(posr)-ask(posl-1) << endl;
    	}
    	
    }
    return ;
}

I - Path Planning

 铜牌题:mex + 二分

我们可以注意到题目要求路径上的mex最大,如果x是可以的那么[1-x]一定是可以的,同时如果x不可以那么[x,..]一定是不可以的,所以具有二分性质,现在核心就是二分,我们可以发现路径一定是右下的走法,也就是满足要求的j一定不会比上面满足要求的j要小否则就是往回走了,由此我们可以得到二分的写法

void solve(){
   
    cin>>n>>m;
    vector<vector<int>> s(n+5,vector<int>(m+5));
    
    for(int i=1;i<=n;i++)
    	for(int j=1;j<=m;j++)
    		cin>>s[i][j];
    
    auto check = [&](int x){
    	int last = 0;
    	for(int i=1;i<=n;i++)
    		for(int j=1;j<=m;j++)
    			if(s[i][j]<x){
    				if(j<last) return false;
    				last = max(last,j);
    			}
    	return true;
    };
    
    int l=1,r=n*m;
    while(l<r){
    	int mid=l+r+1>>1;
    	if(check(mid)) l=mid;
    	else r=mid-1;
    }
    cout << l << endl;
    return ;
}

K - Peg Solitaire

 签到-铜牌题:dfs暴力

可以注意到数据范围是很小的所以我们可以考虑直接暴力因为分支很少dfs的不会很多

按照题目意思模拟暴力即可

int ans;
int dx[]={-1,1,0,0},dy[]={0,0,1,-1};
void dfs(int cnt){
	ans = min(ans,cnt);
	if(ans==1) return ;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++){
			if(s[i][j]){
				for(int u=0;u<4;u++){
					int a=i+dx[u],b=j+dy[u];
					int na=i+2*dx[u],nb=j+2*dy[u];
					if(1<=na and na<=n and 1<=nb and nb<=m
					and s[a][b] and !s[na][nb]){
						s[a][b]=s[i][j]=false;
						s[na][nb]=true;
						dfs(cnt-1);
						s[a][b]=s[i][j]=true;
						s[na][nb]=false;
					}
				}
				
			}
		}
}
void solve(){
   
   	cin>>n>>m>>k;
   	ans = k;
   	memset(s,0,sizeof s);
   	for(int i=1;i<=k;i++){
   		int x,y; cin>>x>>y;
   		s[x][y]=true;
   	}
   	dfs(k);
   	cout << ans << endl;
    return ;
}

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

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

相关文章

【Unity】修改模型透明度

在 Unity 中修改模型透明度主要有两种方法&#xff1a;通过材质和通过着色器。以下是两种方法的步骤和解释&#xff1a; 方法 1&#xff1a;通过材质 在 Unity 编辑器中&#xff0c;选择你想要修改透明度的模型。在 Inspector 窗口中&#xff0c;找到模型的 Renderer 组件&am…

海康WEB3.3控件开发包 V3.3 前端vue项目调用实时监控画面

公司业务迭代, 需要前端vue项目里增加一个查看实时监控模块, 这个需求是之前离职的前端小哥没有研究明白的, 现在落在了我的肩上, 压力还是有的. 但是压力归压力, 问题还是要解决的. 一、调研设备和方案 第一步: 调研大佬们已经实现的方案, 找设备对接. 公司后端大佬提出用官…

Jenkins邮件发送失败问题解决

如下提示为 Extended E-mail Notification开启Debug模式下显示的错误信息&#xff0c; (Debug模式设置方法&#xff1a;Dashboard-> manage Jenkins->configure System)DEBUG SMTP: Attempt to authenticate using mechanisms: LOGIN PLAIN DIGEST-MD5 NTLM XOAUTH2 DEB…

Unity3d 学习之按钮绑定事件

创建测试脚本 using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI;public class myTest : MonoBehaviour {// Start is called before the first frame updatepublic Button _codeBindBtn null;void Start(){if (_codeBi…

LeetCode 213 —— 打家劫舍 II

阅读目录 1. 题目2. 解题思路3. 代码实现 1. 题目 2. 解题思路 此题是 LeetCode 198—— 打家劫舍 的升级版&#xff0c;多了一个首尾相连的设定。 因为首尾相连&#xff0c;所以第一个房屋和最后一个房屋只能偷窃其中一个。 所以&#xff0c;第一种方案就是不偷窃最后一个房…

每日OJ题_DFS爆搜深搜回溯剪枝⑧_力扣980. 不同路径 III

目录 力扣980. 不同路径 III 解析代码 力扣980. 不同路径 III 980. 不同路径 III 难度 困难 在二维网格 grid 上&#xff0c;有 4 种类型的方格&#xff1a; 1 表示起始方格。且只有一个起始方格。2 表示结束方格&#xff0c;且只有一个结束方格。0 表示我们可以走过的空…

HTML5实用大全(Part.1)

引言&#xff1a; 哈喽&#xff0c;各位小伙伴们&#xff0c;在本篇博客我将带领大家走进前端中的HTML5,利用HTML我们将可以在网页上自我创作内容&#xff0c;现在学起来&#xff0c;不久后自己也能制作一个花哨的项目了呢&#xff0c;那么&#xff0c;我们开始吧&#xff01; …

【ROS2学习记录】—— 参考鱼香ROS

1 回顾Linux基础 &#xff08;1&#xff09;打开终端&#xff1a;Ctrl Alt T &#xff08;2&#xff09;ls &#xff08;3&#xff09;cd cd ~ cd /&#xff08;4&#xff09;pwd &#xff08;5&#xff09;mkdir -p catkin_ws/src &#xff08;6&#xff09;rm -rf &#…

LeetCode 198—— 打家劫舍

阅读目录 1. 题目2. 解题思路3. 代码实现 1. 题目 2. 解题思路 此题使用动态规划求解&#xff0c;假设 d p [ i ] [ 0 ] dp[i][0] dp[i][0] 代表不偷窃第 i i i 个房屋可以获得的最高金额&#xff0c;而 d p [ i ] [ 1 ] dp[i][1] dp[i][1] 代表偷窃第 i i i 个房屋可以获…

【右一的开发日记】全导航,持续更新...

文章目录 &#x1f4da;前端【跟课笔记】&#x1f407;核心技术&#x1f407;高级技术 &#x1f4da;捣鼓捣鼓&#x1f407;小小案例&#x1f407;喵喵大王立大功&#x1f407;TED自用学习辅助网站&#x1f407;世界top2000计算机科学家可视化大屏&#x1f407;基于CBDB的唐代历…

GitHub Copilot 简单使用

因为公司安全原因&#xff0c;并不允许在工作中使用GitHub Copilot&#xff0c;所以&#xff0c;一直没怎么使用。最近因为有一些其它任务&#xff0c;所以&#xff0c;试用了一下&#xff0c;感觉还是很不错的。&#xff08;主要是C和Python编程&#xff09; 一&#xff1a;常…

python中的进程线程和协程

目录 进程&#xff08;Process&#xff09;多进程代码实例 线程&#xff08;Thread&#xff09;多线程存在原因及其缺点多线程代码实例 协程&#xff08;Coroutine&#xff09;协程的优点协程代码实例 进程、线程和协程适合的任务性质和环境多进程更适合的场景多线程更适合的场…

LeetCode 11—— 盛最多水的容器

阅读目录 1. 题目2. 解题思路一3. 代码实现一4. 解题思路二5. 代码实现二 1. 题目 2. 解题思路一 暴力法&#xff0c;遍历所有可能的垂线对 ( i , j ) (i, j) (i,j)&#xff0c;求取最大面积&#xff1a; a r e a m i n ( h [ i ] , h [ j ] ) ∗ ( j − i ) area min(h[i]…

Node.js -- MongoDB

文章目录 1. 相关介绍2. 核心概念3. 命令行交互3.1数据库命令3.2 集合命令3.3 文档命令 4. 数据库应用场景4.1 新增4.2 删除4.3 更新4.4 查询 1. 相关介绍 一、简介 Mongodb是什么 MongoDB是一个基于分布式文件存储的数据库&#xff0c;官方地址https://www.mongodb.com/try/d…

一个C++小程序调试过程记录

Top 20 C Projects With Source Code [2024 Update]https://www.interviewbit.com/blog/cpp-projects/ 这个网页有一些简单的C程序的源码&#xff0c;闲来无事&#xff0c;把第一个程序&#xff08;Bookshop Management System Using C&#xff09;的源码下载了下来。 源文件…

第N1周:one-hot独热编码

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 一、OneHot独热编码原理 独热编码&#xff08;One-Hot Encoding&#xff09;是一种将分类数据转换为二进制向量的方法&#xff0c;其中每个类别对应一个唯一的…

如何下载AndroidStudio旧版本

文章目录 1. Android官方网站2. 往下滑找到历史版本归档3. 同意软件下载条款协议4. 下载旧版本Androidstudio1. Android官方网站 点击 Android官网AS下载页面 https://developer.android.google.cn/studio 进入AndroidStuido最新版下载页面,如下图: 2. 往下滑找到历史版本归…

Delta lake with Java--利用spark sql操作数据2

上一篇文章尝试了建库&#xff0c;建表&#xff0c;插入数据&#xff0c;还差删除和更新&#xff0c;所以在这篇文章补充一下&#xff0c;代码很简单&#xff0c;具体如下&#xff1a; import org.apache.spark.sql.SaveMode; import org.apache.spark.sql.SparkSession;publi…

谈一谈电影《飞驰人生》

文章目录 1.概述2.电影情节3.观后感 1.概述 电影《飞驰人生》是一部关于赛车的电影&#xff0c;主要演员是沈腾&#xff0c;因此电影中有不少的喜剧片段&#xff0c;不过电影整体偏向于剧情类电影。该电影的导演是韩寒&#xff0c;就是哪个曾经写出高分高考作文的考生&#xf…

【跟我学RISC-V】(一)认识RISC-V指令集并搭建实验环境

写在前面 现在计算机的体系架构正是发展得如火如荼的时候&#xff0c;占领桌面端市场的x86架构、占领移动端市场的arm架构、在服务器市场仍有一定地位的mips架构、国产自研的指令集loongarch架构、还有我现在要讲到的新型开源开放的RISC-V指令集架构。 我先说一说我的学习经历…
最新文章