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

news2024/11/17 21:54:13

目录

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.coloradmin.cn/o/1637461.html

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

相关文章

labview强制转换的一个坑

32位整形强制转换成枚举的结果如何&#xff1f; 你以为的结果是 实际上的结果是 仔细看&#xff0c;枚举的数据类型是U16&#xff0c;"1"的数据类型是U32&#xff0c;所以转换产生了不可预期的结果。所以使用强制转换时一定要保证两个数据类型一致&#xff0c;否则…

04 - 步骤 JSON input

简介 Kettle 的 JSON Input 步骤是用于从 JSON 格式的数据源中读取数据的步骤。它允许用户指定 JSON 格式的输入数据&#xff0c;然后将其转换成 Kettle 中的行流数据&#xff0c;以供后续的数据处理、转换和加载操作使用。 使用 场景 1、拖拽到面板 2、指定JSON input 为 K…

正点原子[第二期]Linux之ARM(MX6U)裸机篇学习笔记-9.1-LED灯(模仿STM32驱动开发实验)

前言&#xff1a; 本文是根据哔哩哔哩网站上“正点原子[第二期]Linux之ARM&#xff08;MX6U&#xff09;裸机篇”视频的学习笔记&#xff0c;在这里会记录下正点原子 I.MX6ULL 开发板的配套视频教程所作的实验和学习笔记内容。本文大量引用了正点原子教学视频和链接中的内容。…

阿里云开源大模型开发环境搭建

ModelScope是阿里云通义千问开源的大模型开发者社区&#xff0c;本文主要描述AI大模型开发环境的搭建。 如上所示&#xff0c;安装ModelScope大模型基础库开发框架的命令行参数&#xff0c;使用清华大学提供的镜像地址 如上所示&#xff0c;在JetBrains PyCharm的项目工程终端控…

【IDEA】IDEA自带Maven/JDK,不需要下载

IDEA是由Java编写的&#xff0c;为了保证其运行&#xff0c;内部是自带JDK的。IDEA 2021 及 之后的版本是自带Maven的&#xff1a; 视频连接&#xff1a; https://www.bilibili.com/video/BV1Cs4y1b7JC?p4&spm_id_frompageDriver&vd_source5534adbd427e3b01c725714cd…

3-4STM32C8T6按键控制LED开与关

实物接线如下&#xff1a; 为了代码的简洁性&#xff0c;这里需要对LED与KEY进行封装如下&#xff1a; #include "stm32f10x.h" // Device headervoid LED_Init(void) {RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);GPIO_InitTypeDef GP…

粤嵌gec6818开发板-播放视频、音频文件(管道文件控制)

前段时间做了一个项目&#xff0c;用到了linux环境下gec6818开发板播放视频、音频文件&#xff0c;在这里给大家分享一下。 这里使用的方法是利用mplayer播放器进行播放&#xff0c;首先先给开发板装上mplayer播放器&#xff0c;这里就不详细说明了。 我用的是管道文件来控制视…

如何解决DA14531编译工程出现大量报错的问题

在编译DA14531某个工程时&#xff0c;在这台电脑可以编译&#xff0c;另外一台电脑就编译不过&#xff0c;出现很多错误问题。那要怎样处理呢&#xff1f; 建议安装新MDK版本 可能是MDK版本问题&#xff0c;在不同的电脑安装不同的MDK版本&#xff0c;用新的版本可以编译通过&…

ZABAPGIT问题,导入github上的程序包时报 DBSQL_DUPLICATE_KEY_ERROR

跟踪程序发现在94050行 INSERT seocompotx FROM TABLE it_descriptions 报的错 刚开始&#xff0c;不想着改动他&#xff0c;把seocompotx 表的数据做下指定清楚&#xff0c;但是5次清楚后&#xff0c;果断注释掉 改成 MODIFY seocompotx FROM TABLE it_descriptions。 在用…

Winfrom —— 计算阶乘

首先搭建一个界面 创建listBox输入框进行输入内容 界面图如下 计算按钮的事件 private void button1_Click(object sender, EventArgs e) {if (textBox1.Text.Length 0){textBox1.Text "";}else{int n 1;int sum 1;n Convert.ToInt32(textBox1.Text);for (; n…

成像测井基础-1

一、成像测井系统简介 成像测井是一种能探测地层的某个特性(如岩石成分、孔隙度、渗透率)在以井轴为垂直坐标(z)、以井径为径向坐标、以方位角为方向坐标(θ)的柱状坐标系(r&#xff0c;θ,z )中分布的测井方法&#xff0c;且可以按井壁的展开平面或沿某个方位的剖面进行图像显…

Hi3519AV100 处理器⾼速全局快⻔相机

⾼速全局快⻔相机采⽤ 1英⼨全局快⻔ Sensor&#xff0c;⽀持 H.264/H.265 编码&#xff0c;8 百万 分辨率模式下最⾼帧率可达 50 帧/秒&#xff0c;1080P 模式下最⾼帧率可达 120 帧/秒。主控采⽤ Hi3519AV100 处理器&#xff0c;集成 2 Tops AI 算⼒ NPU &#xff0c;⽀持⼤…

必应广告投放怎么做?怎么开户推广?

今天搜索引擎广告依旧是企业提升品牌知名度、吸引潜在客户的关键渠道之一&#xff0c;必应Bing&#xff0c;作为全球第二大搜索引擎&#xff0c;不仅拥有庞大的用户基础&#xff0c;更以其精准的定向能力和高效的转化效率&#xff0c;成为众多企业拓展市场的优选平台。 一、必…

Mysql_数据库事务

文章目录 &#x1f60a; 作者&#xff1a;Lion J &#x1f496; 主页&#xff1a; https://blog.csdn.net/weixin_69252724 &#x1f389; 主题&#xff1a; MySQL__事务&#xff09; ⏱️ 创作时间&#xff1a;2024年04月26日 ———————————————— 这里写目…

基于python的舞蹈经验分享交流网站django+vue

1.运行环境&#xff1a;python3.7/python3.8。 2.IDE环境&#xff1a;pycharmmysql5.7/8.0; 3.数据库工具&#xff1a;Navicat11 4.硬件环境&#xff1a;windows11/10 8G内存以上 5.数据库&#xff1a;MySql 5.7/8.0版本&#xff1b; 运行成功后&#xff0c;在浏览器中输入&am…

Nginx负载均衡主备模式

1. 背景 使用Nginx代理后端服务&#xff0c;有时候某些服务是不能使用多台负载均衡&#xff0c;但又想保障高可用&#xff0c;所以采用主备模式&#xff0c;记录如下&#xff1a; 2. 参考 nginx 负载均衡Nginx-负载均衡-后端状态max_conns、down、backup、max_fails、fail_t…

Docker: 如何不新建容器 修改运行容器的端口

目录 一、修改容器的映射端口 二、解决方案 三、方案 一、修改容器的映射端口 项目需求修改容器的映射端口 二、解决方案 停止需要修改的容器 修改hostconfig.json文件 重启docker 服务 启动修改容器 三、方案 目前正在运行的容器 宿主机的3000 端口 映射 容器…

修改Docker容器内文件的三种方式

说明&#xff1a;本文介绍修改Docker容器内文件的三种方式 方式一&#xff1a;直接修改 敲下面的命令&#xff0c;进入Docker容器&#xff0c;如mysql docker exec -it mysql /bin/bash修改mysql的配置文件&#xff0c;/etc/my.cnf vim /etc/my.cnf如下&#xff0c;如果vim…

【机器学习】基于扩散模型的文本到音频生成:突破数据局限,优化音频概念与实践顺序

基于扩散模型的文本到音频生成&#xff1a;突破数据局限&#xff0c;优化音频概念与时间顺序 一、现有模型的局限与挑战二、偏好数据集的构建与利用三、Diffusion-DPO损失的应用与模型微调四、实例与代码展示五、总结与展望 随着数字化技术的迅猛发展&#xff0c;音乐和电影行业…

霍纳法则与多项式求值问题

目录 多项式求值问题引入 什么是霍尔法则 多项式求值问题引入 题目链接&#xff1a;多项式求值 对于多项式求值问题&#xff0c;例如多项式: 常规的计算方法是每一项单独计算&#xff0c;即先计算&#xff0c;再接着计算&#xff0c;以此类推&#xff0c;最后求和即可&…