蓝桥杯2023年省A(一波三折的)【买瓜】折半搜索+剪枝+排序

题目:洛谷 P9234 [蓝桥杯 2023 省 A] 买瓜


折半搜索

一开始觉得像dp,试着写了,显然过不了,但我实在觉得搜索也过不了啊,去看题解,发现使用了折半搜索(每天都觉得啥都不会捏
折半搜索就是先搜一半,记录下答案,再搜一半,最后把答案整合在一起
比如这题,每个数有三种选法,复杂度3n,折半后就是2*3n/2,大大降低了
但是这个复杂度还是过不了,后面就是不停优化剪枝

剪枝
剪枝1

当前和已经超过m (sum > m)

剪枝2

当前劈瓜次数已经超过历史最优 (k >= ans)

剪枝3

达到同样的和,曾经有过劈瓜数更小的方案 (mp.count(sum) && mp[sum] < k)

折半+剪枝(76分)
用unordered_map更快

#include <vector>
#include <iostream>
#include <cstdio>
#include <map> 
#include <unordered_map>
#include <ctime> 
using namespace std;

typedef long long ll;
const int N = 35;

ll a[N];
int ans = N;
unordered_map<ll, int> mp;//unordered_map更快
ll n, m;

void dfs1(int i, int k, ll sum)
{
	if (sum > m) return;//超了,剪
	if (k >= ans) return;
	if (sum == m)//到了,走了
	{
		ans = min(ans, k);
		return; 
	}
	if (mp.count(sum) && mp[sum] < k) return;//有过更优情况,剪!
	if (i > n / 2)//到头了,把搜到的东西记一下
	{
		//用map记录达到sum的砍刀数最小值
		if (mp.count(sum)) mp[sum] = min(mp[sum], k);
		else mp[sum] = k;
		return;
	}
	//先搜贡献大的更容易找到答案(大概吧
	dfs1(i + 1, k, sum + a[i] + a[i]);//整个
	dfs1(i + 1, k + 1, sum + a[i]);//半个
	dfs1(i + 1, k, sum); //不要
}

void dfs2(int i, int k, ll sum)
{
	if (sum > m) return;
	if (k >= ans) return;
	if (sum == m)
	{
		ans = min(ans, k);
		return; 
	}
	if (i > n)
	{
		//如果另一半有匹配的就更新答案
		if (mp.count(m - sum)) ans = min(ans, k + mp[m - sum]);
		return;
	}
	dfs2(i + 1, k, sum + a[i] + a[i]);
	dfs2(i + 1, k + 1, sum + a[i]);
	dfs2(i + 1, k, sum); 
}
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);
	cin >> n >> m;
	m += m;//为了不出现小数,把a[i]当半个瓜用,那么m也要翻倍
	for (int i = 1; i <= n; i++)
	{
		cin >> a[i];
	}
	dfs1(1, 0, 0);
	dfs2(n/2+1, 0, 0);
	if (ans == N) cout << -1;
	else cout << ans;

	return 0;
}

继续看题解,发现很重要的一点是要给数组排序
为什么呢,不知道,大家都不说
好像挺有道理的但是我说不出道理,先放着

加上sort之后A了


觉得自己无敌了吧?来看看这个
题目 3145: 蓝桥杯2023年第十四届省赛真题-买瓜
欸~一模一样的代码只有82分
最后是怎么过的呢,要把数组从大到小排序
为什么呢
我的理解是,在搜第二段的时候,前面已经出现很多凑到m的情况,使ans变小了,所以第二段会被剪得更狠;相比之下第一段则几乎都要搜到头,所以重点在于要把第一段剪了。那有没有办法让第一段多剪掉一点呢,就让第一段都是大数,sum容易超过m,就会多多被剪了

加上从大到小排序:

sort(a + 1, a + n + 1, greater<int>()); 

正当我欢天喜地地准备结束这题的时候,我手欠地把从大到小版交到了洛谷
嘿——您猜怎么着?TLE了!
好吧我前边都是一顿瞎说(但我真是觉得有道理啊)
那只能是数据问题了,但是数据问题要怎么A啊!

剪枝4

后面我又翻看题解,发现了一个新的剪枝:
预处理后缀和,当前sum加上后缀和也够不到m的话就直接剪
注意这个剪枝只能在第一段中使用,因为第二段本身就要匹配第一段的答案,没法判断会不会不够

void dfs1(int i, int k, ll sum)
{
	if (sum > m) return;
	if (k >= ans) return;
	if (sum + suf[i] < m) return;//注意第i个还没加过,所以是判断sum + suf[i]
	if (sum == m)
	{
		ans = min(ans, k);
		return; 
	}
	if (i > n / 2)
	{
		if (mp.count(sum)) mp[sum] = min(mp[sum], k);
		else mp[sum] = k;
		return;
	}
	dfs1(i + 1, k, sum + a[i] + a[i]);
	dfs1(i + 1, k + 1, sum + a[i]);
	dfs1(i + 1, k, sum); 
}

还有个注意点,要sort之后再算后缀和(对就是我这么傻
以及因为我存的a[i]算半个瓜,算后缀和要算整个瓜,所以要加两次

sort(a + 1, a + n + 1, greater<int>()); 
	suf[n + 1] = 0;
	for (int i = n; i >= 1; i--)
	{
		suf[i] = suf[i + 1] + a[i] + a[i];
	}

贴一个两边都能A的代码

#include <vector>
#include <iostream>
#include <cstdio>
#include <map> 
#include <unordered_map>
#include <ctime> 
#include <algorithm>
using namespace std;

typedef long long ll;
const int N = 35;

ll a[N], suf[N];
int ans = N;
unordered_map<ll, int> mp;
ll n, m;

void dfs1(int i, int k, ll sum)
{
	if (sum > m) return;//超了,剪
	if (k >= ans) return;
	if (sum + suf[i] < m) return;//注意第i个还没加过,所以是判断sum + suf[i]
	if (sum == m)//到了,走了
	{
		ans = min(ans, k);
		return; 
	}
	if (mp.count(sum) && mp[sum] < k) return;//有过更优情况,剪!
	if (i > n / 2)//到头了,把搜到的东西记一下
	{
		//用map记录达到sum的劈瓜数最小值
		if (mp.count(sum)) mp[sum] = min(mp[sum], k);
		else mp[sum] = k;
		return;
	}
	//先搜贡献大的更容易找到答案(大概吧
	dfs1(i + 1, k, sum + a[i] + a[i]);//整个
	dfs1(i + 1, k + 1, sum + a[i]);//半个
	dfs1(i + 1, k, sum); //不要
}

void dfs2(int i, int k, ll sum)
{
	if (sum > m) return;
	if (k >= ans) return;
	if (sum == m)
	{
		ans = min(ans, k);
		return; 
	}
	if (i > n)
	{
		//如果另一半有匹配的就更新答案
		if (mp.count(m - sum)) ans = min(ans, k + mp[m - sum]);
		return;
	}
	dfs2(i + 1, k, sum + a[i] + a[i]);
	dfs2(i + 1, k + 1, sum + a[i]);
	dfs2(i + 1, k, sum); 
}
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);
	cin >> n >> m;
	m += m;//为了不出现小数,把a[i]当半个瓜用,那么m也要翻倍
	for (int i = 1; i <= n; i++)
	{
		cin >> a[i];
	}
	//sort(a + 1, a + n + 1); 
	sort(a + 1, a + n + 1, greater<int>()); 
	suf[n + 1] = 0;
	for (int i = n; i >= 1; i--)
	{
		suf[i] = suf[i + 1] + a[i] + a[i];
	}
	dfs1(1, 0, 0);
	dfs2(n/2+1, 0, 0);
	if (ans == N) cout << -1;
	else cout << ans;
	
	return 0;
}

结果就是加上这个剪枝从大到小排序洛谷能过了,但是从小到大c语言网不行,继续看!


其他优化

我就不写了感觉好麻烦要把之前写的推翻重来orz

二分

不直接搜i+1,而是根据还需要的斤数在剩下的瓜里二分(因为已经排序了嘛),大于还需要的斤数的瓜可以不用考虑
(这样二分甚至可以不用折半搜索
见 P9234 [蓝桥杯 2023 省 A] 买瓜 题解

手写哈希表

大概是因为unordered_map还是常数大了吧(
见 买瓜 题解


参考

P9234 [蓝桥杯 2023 省 A] 买瓜 题解
买瓜 题解
买瓜题解


菜死我算了,真在赛场上碰到这种题我就拿个30分吧(默哀

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

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

相关文章

CentOS部署 JavaWeb 实现 MySql业务

一、项目打war包 在eclispe或idea中找到项目&#xff0c;右键打war包。 二、上传项目到linux 2.1云服务器虚拟机均可 以tomcat为例 /usr/local/tomcat/webapps 将war包通过ssh连接上传到webapps目录下。 如果是root目录则不需要项目名即 ip或域名端口直接访问&#xff08…

数学建模-估计出租车的总数

文章目录 1、随机抽取的号码在总体的排序 1、随机抽取的号码在总体的排序 10个号码从小到大重新排列 [ x 0 , x ] [x_0, x] [x0​,x] 区间内全部整数值 ~ 总体 x 1 , x 2 , … , x 10 总体的一个样本 x_1, x_2, … , x_{10} ~ 总体的一个样本 x1​,x2​,…,x10​ 总体的一个样…

Linux磁盘配额

磁盘配额 概述 Linux系统作为一个多用户的操作系统&#xff0c;在生产环境中&#xff0c;会发生多个用户共同使用一个磁盘的情况&#xff0c;会造成Linux根分区的磁盘空间耗尽&#xff0c;导致Linux系统无法建立新的文件&#xff0c;从而出现服务程序崩溃、系统无法启动等故障…

Elasticsearch:调整搜索速度

在我之前的文章 “Elasticsearch&#xff1a;如何提高查询性能” 及 “Elasticsearch&#xff1a;提升 Elasticsearch 性能” 里&#xff0c;我详细描述了如何提高搜索的性能。在今天的文章里&#xff0c;我从另外一个视角来描述如何调整搜索的速度。希望对大家有所帮助&#x…

c++简单实现avl树

文章目录 AVL树节点类节点类的构造函数 AVLinsert()插入RotateL(左单旋)RotateR(右单旋)RotateLR(右双旋)RotateRL(左双旋) Find(查找)IsBalance(检查是否是avl树) AVL树 AVL树:又名高度平衡树&#xff0c;在二叉搜索树的基础上加上了一个条件&#xff0c;条件是左右子树高度差…

【并查集】模版

【模板】并查集 - 洛谷 #include <bits/stdc.h> using namespace std; const int N2e59; int a[N]; int Find(int x) {if(xa[x]){return x;}else{a[x]Find(a[x]);return a[x];} } void push(int x,int y) {a[Find(x)]Find(y);return ; } int main() {int n,m; cin>>…

(十七)【Jmeter】取样器(Sampler)之JSR223取样器

该实例使用python 2.7.3的插件,jython-standalone-2.7.3.jar:https://www.123pan.com/s/VppKjv-5YvTv.html 提取码:tfsX 把该插件放在Jmeter安装的:apache-jmeter-5.6.3\lib\ext目录下: 简述 JSR是Java Specification Requests的缩写,意思是Java规范提案 操作路径如下: …

Linux-新手小白速秒Hadoop集群全生态搭建(图文混编超详细)

在之前的文章中&#xff0c;我教会大家如何一步一步搭建一个Hadoop集群&#xff0c;但是只提供了代码&#xff0c;怕有些朋友会在一些地方产生疑惑&#xff0c;今天我来以图文混排的方式&#xff0c;一站式交给大家如何搭建一个Hadoop高可用集群包括&#xff08;HadoopHA&#…

鸿蒙Harmony应用开发—ArkTS声明式开发(容器组件:SideBarContainer)

提供侧边栏可以显示和隐藏的侧边栏容器&#xff0c;通过子组件定义侧边栏和内容区&#xff0c;第一个子组件表示侧边栏&#xff0c;第二个子组件表示内容区。 说明&#xff1a; 该组件从API Version 8开始支持。后续版本如有新增内容&#xff0c;则采用上角标单独标记该内容的起…

第九届多媒体系统和信号处理国际会议(ICMSSP 2024)即将召开!

2024年第九届多媒体系统和信号处理国际会议&#xff08;ICMSSP 2024&#xff09;将在5月24-26日在泰国曼谷举行。ICMSSP 2024旨在展示多媒体系统和信号处理等相关主题的最新研究和成果&#xff0c;为不同领域的专家代表提供了面对面交流新想法以及应用经验的机会&#xff0c;建…

【经验总结】ubuntu 20.04 git 上传本地文件给 github,并解决出现的问题

1. 在GitHub 上创建仓库 登录 GitHub 个人网站 点击 New 填写 Repository name, 以及 Description (optional) 选择 Public &#xff0c; 并添加 Add a README file 点击 Create repository github repository 创建成功 2. 设置SSH key 在本地 bash 运行&#xff1a;…

sqllab第十八关通关笔记

知识点&#xff1a; UA注入 不进行url解析&#xff0c;不能使用 %20 编码等操作出现在User-agent字段中一般为insert语句 insert 表名(字段1&#xff0c;字段2&#xff0c;。。。) values(数据1&#xff0c;数据2&#xff0c;。。。) 通过admin admin进行登录发现页面打印出了…

arp动态表缓存清除

一、arp表里清除表状态&#xff1a; 1&#xff0c;Delay&#xff1a;请求arp 2&#xff0c;Reachab&#xff1a;响应arp 3&#xff0c;Stale此状态下&#xff0c;待gc_stale_time超时后&#xff0c;准备gc_interval定期清理 二、限制条件 base_reachable_time&#xff1a;后变…

数据结构的概念大合集04(队列)

概念大合集04 1、队列1.1 队列的定义1.2队列的顺序存储1.2.1 顺序队1.2.2 顺序队的基本运算的基本思想1.2.3 顺序队的4要素的基本思想 1.3 环形队列1.3.1 环形队列的定义1.3.1 环形队列的实现 1.4 队列的链式存储1.4.1 链队1.4.2 链队的实现方式1.4.3 链队的4要素的基本思想 1.…

双指针 | 移动零 | 复写零

1.移动零 题目描述&#xff1a; 给定一个数组 nums&#xff0c;编写一个函数将所有 0 移动到数组的末尾&#xff0c;同时保持非零元素的相对顺序。 示例&#xff1a; 输入: nums [0,1,0,3,12] 输出: [1,3,12,0,0]解题思路&#xff1a; right指针一直往后移动&#xff0c;当…

Java实现简单的通讯录

每日一言 泪眼问花花不语&#xff0c;乱红飞过秋千去。 —欧阳修- 简单的通讯录实现&#xff0c;跟写Java实现图书管理系统差不多&#xff0c;用到的知识也差不多&#xff0c;就当个小练习&#xff0c;练习一下写Java程序的手感。 Java实现图书管理系统 关于通讯录的代码都写…

【JVM】(内存区域划分 为什么要划分 具体如何分 类加载机制 类加载基本流程 双亲委派模型 类加载器 垃圾回收机制(GC))

文章目录 内存区域划分为什么要划分具体如何分 类加载机制类加载基本流程双亲委派模型类加载器 垃圾回收机制&#xff08;GC&#xff09; 内存区域划分 为什么要划分 JVM启动的时候会申请到一整个很大的内存区域,JVM是一个应用程序,要从操作系统这里申请内存,JVM就需要根据,把…

Android Studio字体大小调节

外观页面字体调节 settings->Appearance->User cunstom font 代码字体调节 Settings->Editor->Font此时logcat窗口、Build窗口和Ternimal窗口字体大小也会同步调节&#xff08;2023.2.1版本上验证&#xff09;

基于Springboot和Redis实现的快递代取系统

1.项目简介 本项目基于springboot框架开发而成&#xff0c;前端采用bootstrap和layer框架开发&#xff0c;系统功能完整&#xff0c;界面简洁大方&#xff0c;比较适合做毕业设计使用。 本项目主要实现了代取快递的信息管理功能&#xff0c;使用角色有三类&#xff1a;一是客…

Elasticsearch 主副分片切换过程中对业务写入有影响吗

&#x1f34a;&#x1f349;&#x1f34b; 先说下结论&#xff0c;只要集群中的工作节点过半&#xff0c;有候选的master节点&#xff0c;挂掉的节点中不同时包含索引的主分片和副分片&#xff0c;那么ES是可以做到让业务无感知的进行主副分片切换的。 蓝胖子会先讲解下ES集群写…