首页 > 其他分享 >P8453 「SWTR-8」美元巨大 (位运算+贪心)

P8453 「SWTR-8」美元巨大 (位运算+贪心)

时间:2024-07-05 10:20:12浏览次数:15  
标签:nxt cnt P8453 int sum SWTR lst need 贪心

P8453 「SWTR-8」美元巨大

位运算+贪心

因为 \(a_i=2^{b_i}\),所以每一个符号只会影响一个二进制位,也就是二进制位是独立的。

考虑经典的按位考虑,从高位到低位,我们希望高位尽可能取到 \(1\) 并且留下更好的符号让低位能更大。考虑贪心,显然 |^ 的价值更大,所以在答案不会变小的情况下尽量用 ^

如果 \(cnt_{b_i}\) 为奇数,那么全部填 ^ 就可以取到 \(1\),不够就补 |

如果 \(cnt_{b_i}\) 为偶数,那么至少需要一个 | 放在最后面的 \(b_i\) 前面才能取到 \(1\),其他都用 ^,不够只能补 |。如果没有 |,那就取不到 \(1\) 了。

注意 \(a_1\) 前面不用填符号,需要判断一下。要预处理 \(nxt_i\) 表示前一个 \(b_i\) 的位置在哪里。

复杂度 \(O(T\max(a_i))\)。

#include <bits/stdc++.h>
#define pii std::pair<int, int>
#define mk std::make_pair
#define fi first
#define se second
#define pb push_back

using i64 = long long;
using ull = unsigned long long;
const i64 iinf = 0x3f3f3f3f, linf = 0x3f3f3f3f3f3f3f3f;
const int N = 75010;
int s, t, n, x, y;
int cnt[N], nxt[N], lst[N], b[N], f[N];
void solve() {
	std::cin >> n >> x >> y;

	int mx = 0, fi;
	std::cin >> fi;
	cnt[fi]++;
	lst[fi] = 1;
	mx = std::max(mx, fi);
	for (int i = 2; i <= n; i++) {
		int a;
		std::cin >> a;
		cnt[a]++;
		mx = std::max(mx, a);
		nxt[i] = lst[a];
		lst[a] = i;
	}

	for (int i = mx; i >= 0; i--) {
		int need;
		if(i == fi) need = cnt[i] - 1;
		else need = cnt[i];
		if(!need) {
			if(i == fi) f[i] = 1;
			continue;
		}
		if(cnt[i] & 1) {
			if(x >= need) {
				for (int j = lst[i]; j; j = nxt[j]) {
					b[j] = 0;
				} 
				x -= need;
				f[i] = 1;
			} else {
				int sum = 0;
				for (int j = lst[i]; j; j = nxt[j]) {
					if(x >= need - sum) {
						b[j] = 0;
					} else if(j != 1) b[j] = 1, sum++;
				}
				x = 0, y -= sum;
				f[i] = 1;
			}
		} else {
			if(y) {
				if(x >= need - 1) {
					b[lst[i]] = 1;
					for (int j = lst[nxt[i]]; j; j = nxt[j]) {
						b[j] = 0;
					} 
					x -= need - 1, y--;
					f[i] = 1;
				} else {
					int sum = 0;
					for (int j = lst[i]; j; j = nxt[j]) {
						if(x >= need - sum) {
							b[j] = 0;
						} else if(j != 1) b[j] = 1, sum++;
					}
					x = 0, y -= sum;
					f[i] = 1;
				}
			} else {
				for (int j = lst[i]; j; j = nxt[j]) {
					b[j] = 0;
				}
			}
		}
	}
	int lim = 0;
	for(int i = mx; i >= 0; i--) {
		if(!lim && f[i]) {
			std::cout << f[i];
			lim = 1;
		} else if(lim) std::cout << f[i];
	}
	if(!lim) std::cout << "0";
	std::cout << "\n";

	for(int i = 2; i <= n; i++) {
		std::cout << (b[i] ? "|" : "^");
	}
	std::cout << "\n";

	for(int i = 0; i <= mx; i++) f[i] = cnt[i] = lst[i] = 0;
	for(int i = 1; i <= n; i++) b[i] = nxt[i] = 0;
}
int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    
    std::cin >> s >> t;

	while(t--) solve();

	return 0;
}

标签:nxt,cnt,P8453,int,sum,SWTR,lst,need,贪心
From: https://www.cnblogs.com/FireRaku/p/18285238

相关文章

  • CF1039D You Are Given a Tree (树形 dp + 贪心 + 根号分治)
    CF1039DYouAreGivenaTree树形dp+贪心+根号分治题目是一个经典问题,可以用树形dp和贪心解决。设\(f_u\)表示以\(u\)节点为端点能够剩下的最长路径。考虑从叶子节点往上合并贪心,那么如果能够合并出包含\(u\)节点的大于等于\(k\)的路径,那么就合并,\(f_u=0\);否......
  • 贪心经典例题:均分纸牌
    希望粉丝破50. 贪心实际上就是把眼前的利益最大化,如果你要做出这道题你一定要找出贪心原则。贪心原则https://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=1&rsv_idx=1&tn=baidu&wd=%E8%B4%AA%E5%BF%83%E5%8E%9F%E5%88%99&fenlei=256&rsv_pq=0xb087efe300ab5a2d&rsv_t=78216%2Bh......
  • 贪心推公式——AcWing 125. 耍杂技的牛
    贪心推公式定义贪心算法是一种在每一步选择中都采取在当前状态下最优的选择,希望通过局部的最优选择来得到全局最优解的算法策略。运用情况问题具有最优子结构,即一个问题的最优解包含其子问题的最优解。可以通过局部最优决策逐步推导到全局最优。问题的选择策略相对明确且易......
  • LeetCode 2542. 最大子序列的分数(贪心、小顶堆)
    2542.最大子序列的分数思路:先对nums2按降序排列,然后遍历nums2的最小值,同时在区间[0,i]中选中k个最大的nums1即可。然后找出最大的ansclassSolution{public:typedefpair<int,int>PII;longlongmaxScore(vector<int>&nums1,vector<int>&nums2,intk)......
  • (nice!!!)LeetCode LCP 20. 快速公交(记忆化搜索+小顶堆+贪心)
    LCP20.快速公交思路:逆向记忆化搜索。思考从target到0所花的最小时间。通过哈希表来进行记忆化搜索,避免重复遍历。细节看注释classSolution{public:typedeflonglongLL;typedefpair<LL,LL>PII;constintmod=1e9+7;intbusRapidTransit(int......
  • 蓝桥杯课程-贪心算法讲解
    1.区间调度问题问题描述在有限的区间范围内,选择完成最多的任务组合解决策略我们可以思考的策略有:1.最早开始时间(begin)2.最早结束时间(end)3.用时最少(end-begin)1.我们这里首先定方向:从区间最左端向右开始选择。2.我们很容易想到的策略是选择用时最少的情况,但是试想如果......
  • 小于n的最大数 - 贪心算法及证明 - 附python实现
    一、问题描述?    给定一个整数n,并从1~9中给定若干个可以使用的数字,根据上述两个条件,得到每一位都为给定可使用数字的、最大的小于整数n的数。    例如,给定可以使用的数字为{2,3,8}三个数:    给定n=3589,输出3388;给定n=8234,输出8233;…… 二、解......
  • 【Py/Java/C++三种语言OD独家2024D卷真题】20天拿下华为OD笔试之【贪心/脑筋急转弯】2
    有LeetCode算法/华为OD考试扣扣交流群可加948025485可上全网独家的欧弟OJ系统练习华子OD、大厂真题绿色聊天软件戳od1441了解算法冲刺训练(备注【CSDN】否则不通过)文章目录题目描述与示例题目描述输入描述输出描述示例一输入输出说明示例二输入输出说明示例三......
  • (nice!!!)LeetCode 2813. 子序列最大优雅度(反悔贪心)
    2813.子序列最大优雅度思路:1.先对数组items按profit进行降序排序。2.把前k个最大的profit选中3.再遍历剩余的项目,看看能不能增加类别的数量。因为profit是递减的,所以只有类别的数量能增大的情况下,才考虑从选中的k个项目当中删掉重复的类别项目里面的最小profit。细节......
  • 反悔贪心学习笔记
    算法:反悔贪心,顾名思义就是贪心的时候反悔。意思是:如果这一步的贪心不是全局最优解,就退回去一步,换一种贪心策略。一般分为反悔自动机和反悔堆。反悔自动机基本的思路是:每次选择直观上最接近全局最优解的贪心策略,若发现最优解不对,就想办法自动支持反悔策略。反悔堆则......