Codeforces Round 939 (Div. 2) D. Nene and the Mex Operator 题解 二进制枚举+递归

2024-05-09 19:44

本文主要是介绍Codeforces Round 939 (Div. 2) D. Nene and the Mex Operator 题解 二进制枚举+递归,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Nene and the Mex Operator

题目描述

Nene给了你一个长度为 n n n 的整数数组 a 1 , a 2 , … , a n a_1, a_2, \ldots, a_n a1,a2,,an

你可以执行以下操作不超过 5 ⋅ 1 0 5 5\cdot 10^5 5105 次(可能为零):

  • 选择两个整数 l l l r r r ,使得 1 ≤ l ≤ r ≤ n 1 \le l \le r \le n 1lrn ,计算 x x x MEX ⁡ ( { a l , a l + 1 , … , a r } ) \operatorname{MEX}(\{a_l, a_{l+1}, \ldots, a_r\}) MEX({al,al+1,,ar}) ,同时设置 a l = x , a l + 1 = x , … , a r = x a_l=x, a_{l+1}=x, \ldots, a_r=x al=x,al+1=x,,ar=x

这里,整数集合 { c 1 , c 2 , … , c k } \{c_1, c_2, \ldots, c_k\} {c1,c2,,ck} 中的 MEX ⁡ \operatorname{MEX} MEX 被定义为在集合 c c c 中不出现的最小非负整数 m m m

你的目标是最大化数组 a a a 中元素的和。找出最大和,并构建一个操作序列来实现这个和。需要注意的是,你不需要最小化这个序列中的运算次数,你只需在解决方案中使用不超过 5 ⋅ 1 0 5 5\cdot 10^5 5105 的运算。

输入描述

第一行包含一个整数 n n n 1 ≤ n ≤ 18 1 \le n \le 18 1n18 )- 数组 a a a 的长度。

第二行包含 n n n 个整数 a 1 , a 2 , … , a n a_1,a_2,\ldots,a_n a1,a2,,an 0 ≤ a i ≤ 1 0 7 0\leq a_i \leq 10^7 0ai107 )。

输出描述

在第一行中,输出两个整数 s s s m m m ( 0 ≤ m ≤ 5 ⋅ 1 0 5 0\le m\le 5\cdot 10^5 0m5105 ) - 数组 a a a 元素的最大和以及解决方案中的操作数。

在下面 m m m 行的 i i i -th 中,输出两个整数 l l l r r r ( 1 ≤ l ≤ r ≤ n 1 \le l \le r \le n 1lrn ),代表 i i i -th 运算的参数。

可以证明,数组 a a a 元素的最大和总是可以通过不超过 5 ⋅ 1 0 5 5 \cdot 10^5 5105 次的运算得到。

样例输入1

2
0 1

样例输出1

4 1
1 2

样例输入2

3
1 3 9

样例输出2

13 0

样例输入3

4
1 100 2 1

样例输出3

105 2
3 3
3 4

样例输入4

1
0

样例输出4

1 1
1 1

原题

CF Round 939——传送门

思路

对于任意一段区间 [ l , r ] [l,r] [l,r],我们总能进行一系列操作,使该区间的和为 ( r − l + 1 ) ∗ ( r − l + 1 ) (r-l+1)*(r-l+1) (rl+1)(rl+1)。所以,由于数组的长度最大为 18 18 18,我们可以通过二进制枚举所有对区间操作的方案数,找到使得和最大的其中一种方案。找到了使和最大的方案后,需要输出对于各个区间的操作。那么我们考虑任意一段区间 [ l , r ] [l,r] [l,r],先将其中所有元素置 0 0 0,因为需要将该区间转化为 { r − l + 1 , r − l + 1 , … , r − l + 1 } \{r-l+1, r-l+1, \ldots, r-l+1\} {rl+1,rl+1,,rl+1},所以先递归得到 { r − l , r − l , … , r − l , r − l , 0 } \{r-l, r-l, \ldots, r-l , r-l,0\} {rl,rl,,rl,rl,0},然后将 [ l , r − 2 ] [l,r-2] [l,r2]的部分置 0 0 0,进行不断递归,直至区间转化为 { 1 , 2 , 3 , … , r − l , 0 } \{1, 2, 3, \ldots, r-l,0\} {1,2,3,,rl,0},然后再对整个区间进行一次操作,即可得到 { r − l + 1 , r − l + 1 , … , r − l + 1 } \{r-l+1, r-l+1, \ldots, r-l+1\} {rl+1,rl+1,,rl+1}

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;void set_zero(int l, int r, vector<int> &a, vector<pair<int, int>> &ans)
{for (int i = l; i <= r; i++){if (a[i] != 0){ans.push_back({i, i});}}
}void set_max(int l, int r, vector<pair<int, int>> &ans)
{if (l == r){ans.push_back({l, r});return;}for (int k = r - 1; k >= l; k--){set_max(l, k, ans);if (k != l)ans.push_back({l, k - 1});}ans.push_back({l, r});
}int main()
{ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);// 对于任意一段区间[l,r],我们总能进行一系列操作,使该区间的和为 (r-l+1)*(r-l+1)// 所以,由于数组的长度最大为18,我们可以通过二进制枚举所有对区间操作的方案数,找到使得和最大的其中一种方案int n;cin >> n;vector<int> a(n);for (auto &x : a)cin >> x;vector<pair<int, int>> op;         // 记录和最大时需要操作的区间int max_sum = 0;                   // 记录最大和for (int i = 0; i < (1 << n); i++) // 二进制枚举所有区间操作方案,连续的一段1是需要进行区间操作的{ll sum = 0;                 // 当前方案的总和vector<pair<int, int>> tmp; // 当前方案需要操作的区间for (int j = 0; j < n;){if ((i >> j) & 1){int l = j;int r = j;r++;while (r < n && ((i >> r) & 1)) // 找到连续的一段1{r++;}tmp.push_back({l, r - 1});sum += (r - l) * (r - l); // 找到的区间为[l,r)j = r;}else{sum += a[j];j++;}}if (sum > max_sum){op = tmp;max_sum = sum;}}cout << max_sum << ' '; // 输出最大和// 那么下面的任务就是输出实现这种方案的所需操作vector<pair<int, int>> ans; // 记录所需操作// 先将区间元素全部置0for (int i = 0; i < op.size(); i++){set_zero(op[i].first, op[i].second, a, ans);}// 再将区间元素全部化为r-l+1for (int i = 0; i < op.size(); i++){set_max(op[i].first, op[i].second, ans);}// 输出操作cout << ans.size() << '\n';for (int i = 0; i < ans.size(); i++){cout << ans[i].first + 1 << ' ' << ans[i].second + 1 << '\n';}return 0;
}

这篇关于Codeforces Round 939 (Div. 2) D. Nene and the Mex Operator 题解 二进制枚举+递归的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/974322

相关文章

如何将二进制文件流转化为MockMultipartFile文件

《如何将二进制文件流转化为MockMultipartFile文件》文章主要介绍了如何使用Spring框架中的MockMultipartFile类来模拟文件上传,并处理上传逻辑,包括获取二进制文件流、创... 目录一、名词解释及业务解释1.具体业务流程2.转换对象解释1. MockMultipartFile2

C#实现获得某个枚举的所有名称

《C#实现获得某个枚举的所有名称》这篇文章主要为大家详细介绍了C#如何实现获得某个枚举的所有名称,文中的示例代码讲解详细,具有一定的借鉴价值,有需要的小伙伴可以参考一下... C#中获得某个枚举的所有名称using System;using System.Collections.Generic;usi

Java 枚举的常用技巧汇总

《Java枚举的常用技巧汇总》在Java中,枚举类型是一种特殊的数据类型,允许定义一组固定的常量,默认情况下,toString方法返回枚举常量的名称,本文提供了一个完整的代码示例,展示了如何在Jav... 目录一、枚举的基本概念1. 什么是枚举?2. 基本枚举示例3. 枚举的优势二、枚举的高级用法1. 枚举

Rust中的Option枚举快速入门教程

《Rust中的Option枚举快速入门教程》Rust中的Option枚举用于表示可能不存在的值,提供了多种方法来处理这些值,避免了空指针异常,文章介绍了Option的定义、常见方法、使用场景以及注意事... 目录引言Option介绍Option的常见方法Option使用场景场景一:函数返回可能不存在的值场景

hdu 2489 (dfs枚举 + prim)

题意: 对于一棵顶点和边都有权值的树,使用下面的等式来计算Ratio 给定一个n 个顶点的完全图及它所有顶点和边的权值,找到一个该图含有m 个顶点的子图,并且让这个子图的Ratio 值在所有m 个顶点的树中最小。 解析: 因为数据量不大,先用dfs枚举搭配出m个子节点,算出点和,然后套个prim算出边和,每次比较大小即可。 dfs没有写好,A的老泪纵横。 错在把index在d

Codeforces Round #240 (Div. 2) E分治算法探究1

Codeforces Round #240 (Div. 2) E  http://codeforces.com/contest/415/problem/E 2^n个数,每次操作将其分成2^q份,对于每一份内部的数进行翻转(逆序),每次操作完后输出操作后新序列的逆序对数。 图一:  划分子问题。 图二: 分而治之,=>  合并 。 图三: 回溯:

Codeforces Round #261 (Div. 2)小记

A  XX注意最后输出满足条件,我也不知道为什么写的这么长。 #define X first#define Y secondvector<pair<int , int> > a ;int can(pair<int , int> c){return -1000 <= c.X && c.X <= 1000&& -1000 <= c.Y && c.Y <= 1000 ;}int m

Codeforces Beta Round #47 C凸包 (最终写法)

题意慢慢看。 typedef long long LL ;int cmp(double x){if(fabs(x) < 1e-8) return 0 ;return x > 0 ? 1 : -1 ;}struct point{double x , y ;point(){}point(double _x , double _y):x(_x) , y(_y){}point op

Codeforces Round #113 (Div. 2) B 判断多边形是否在凸包内

题目点击打开链接 凸多边形A, 多边形B, 判断B是否严格在A内。  注意AB有重点 。  将A,B上的点合在一起求凸包,如果凸包上的点是B的某个点,则B肯定不在A内。 或者说B上的某点在凸包的边上则也说明B不严格在A里面。 这个处理有个巧妙的方法,只需在求凸包的时候, <=  改成< 也就是说凸包一条边上的所有点都重复点都记录在凸包里面了。 另外不能去重点。 int

C++ | Leetcode C++题解之第393题UTF-8编码验证

题目: 题解: class Solution {public:static const int MASK1 = 1 << 7;static const int MASK2 = (1 << 7) + (1 << 6);bool isValid(int num) {return (num & MASK2) == MASK1;}int getBytes(int num) {if ((num &