yzoi2223集合构造的详细解法

Description - 问题描述

集合M的定义如下:

  • 1是M中的元素
  • 如果x是M中的元素,那么2x+1和4x+5都是M中的元素

那么,集合M中,最小的n个数是哪些?

Input - 输入数据

一个整数n(1<=n<=100 000)

Output - 输出数据

n个从小到大的整数,空格分隔。

  仔细一分析便可推知最后需要输出的数一定是单调递增的。在当时做这题的时候,旁边的gxy同学直接从1开始暴力枚举所有的奇数(2x+1和4x+5肯定是一个奇数),然后判断和前面的数是否构成2x+1或4x+5的关系,是的话就输出,否则便continue,这样的话算法复杂度就达到了O(n^2),最后还是有一个点无法通过。那么,是否还有更好的方法呢?

  事实上,由前面的单调递增可以知道:假如我们用一个数组来保存输出的数,那么这个数组肯定是2x+1产生的数再并上4x+5产生的数。这样一来也就明了了只要我们定义一个a队列来保存2x+1产生的数,用一个b队列保存4x+5产生的数。每次将a的对头与b的对头进行比较,则会出现3种情况:(A)a对头>b对头  (B)a对头=b对头  (C)a对头<b对头  这时只需要将较小者送人x来执行下一次的2x+1和4x+5,同时也不要忘记将x输出。在经过多方的查证后,我才得以知道这是使用了单调队列的思想,下面给出百度里给它的定义以有助于大家的理解:单调队列,即单调的队列。使用频率不高,但在有些程序中会有非同寻常的作用。(大概就是诸如这类的题目吧)

举例

不妨用一个问题来说明单调队列的作用和操作:

不断地向缓存数组里读入元素,也不时地去掉最老的元素,不定期的询问当前缓存数组里的最小的元素。

最直接的方法:普通队列实现缓存数组。

进队出队都是O(1),一次查询需要遍历当前队列的所有元素,故O(n)。

  好了,接下来给出代码,仅供参考:

 1 #include<iostream>
 2 using namespace std;
 3 const int maxn=1000000+10;
 4 int a[maxn],b[maxn];
 5 int x=1,n,total=1;
 6 int front1=1,front2=1,tail1=0,tail2=0;
 7 int main()
 8 {
 9     cin>>n;
10     while(total<=n)
11     {
12         if(total==n)
13         cout<<x;
14         else
15         cout<<x<<‘ ‘;
16
17         tail1++;
18         a[tail1]=2*x+1;
19
20         tail2++;
21         b[tail2]=4*x+5;
22
23         if(a[front1]>b[front2])
24         {
25             x=b[front2];
26             front2++;
27
28         }
29         else
30         {
31             if(a[front2]<b[front2])
32             {
33             x=a[front1];
34             front1++;
35             }
36             else
37             {
38                 x=a[front1];
39                 front1++;
40                 front2++;
41             }
42         }
43         total++;
44     }
45     return 0;
46 }

最后,欢迎大家的指教。

时间: 2024-12-11 01:23:49

yzoi2223集合构造的详细解法的相关文章

几何算法:点集合构造简单多边形

问题:给定平面中n个点所组成的集合,将它们连接起来形成一条简单的封闭路径.所谓简单路径,是指边与边无交叉. 如下图所示10个点组成的简单轮廓: 思路:取x坐标最大的点A(如果最大x坐标的点不止一个,则取Y坐标最小的点),依次计算A点与其余各点的连线与水平线之间夹角的正切值,然后按照正切值排序,依次连接排序后的各点即组成一个简单图形. 原理:其它所有点都在A点的左侧,所有夹角的范围为-Pi/2~Pi/2,单调递增函数. 举一个例子如下: 各点坐标与A点的角度斜率如下(已经排序好): x:426.1

yzoi2226最小步数的详细解法

Description - 问题描述 在各种棋中,棋子的走法总是一定的,如中国象棋中马走“日”.有一位小学生就想如果马能有两种走法将增加其趣味性,因此,他规定马既能按“日”走,也能如象一样走“田”字.他的同桌平时喜欢下围棋,知道这件事后觉得很有趣,就想试一试,在一个(100*100)的围棋盘上任选两点A.B,A点放上黑子,B点放上白子,代表两匹马.棋子可以按“日”字走,也可以按“田”字走,俩人一个走黑马,一个走白马.谁用最少的步数走到左上角坐标为(1,1)的点时,谁获胜.现在他请你帮忙,给你A.

C#基础[10] ArrayList集合(二)【详细介绍】

1.什么是ArrayList ArrayList就是传说中的动态数组,用MSDN中的说法,就是Array的复杂版本,它提供了如下一些好处: 动态的增加和减少元素 实现了ICollection和IList接口 灵活的设置数组的大小 2.如何使用ArrayList 最简单的例子: ArrayList List = new ArrayList(); for( int i=0;i<10;i++ ) //给数组增加10个Int元素 List.Add(i); //..程序做一些处理 List.RemoveA

Springmvc构造RESTful详细讲解

/blog/1 HTTP GET => 得到id = 1的blog/blog/1 HTTP DELETE => 删除 id = 1的blog/blog/1 HTTP PUT => 更新id = 1的blog/blog HTTP POST => 新增BLOG 以下详细解一下spring rest使用. 首先,我们带着如下两个问题查看本文. 1.如何在java构造没有扩展名的RESTful url,如 /forms/1,而不是 /forms/1.do 2.浏览器的form标签不支持提交

yzoi1777倒水问题的详细解法

Description - 问题描述 x.y.z三个容器,其最大容量分别是xMAX升.yMAX升.zMAX升,这里规定100>xMAX>yMAX>zMAX.一开始x是装满了水的,现在要用这三个没有刻度的容器量出n升水来,请打印出最少的量取步骤. Input - 输入数据 输入只有一行,即4个整数: xMax  yMax  zMax n 其中100>xMax>yMax>zMax,n<100 Output - 输出数据 对于每个测试数据,输出其倒水步骤,如果步骤只有一

[LeetCode系列] 从中序遍历和后序遍历序列构造二叉树(迭代解法)

给定中序遍历inorder和后序遍历postorder, 请构造出二叉树. 算法思路: 设后序遍历为po, 中序遍历为io. 首先取出po的最后一个节点作为根节点, 同时将这个节点入stn栈; 随后比较io的最后一个节点和stn栈顶节点: 如果不同则将此节点添加到栈顶节点的右侧并入stn栈, 同时从po中删除这个节点; 此时的栈中保存了所有还未处理左子树的右侧根节点 出现一次不同, 右侧子树的深度就增加1, 栈的深度就代表了当前右侧子树的深度 如果相同, 先缓存栈顶节点, 分别删除io和栈顶元素

集合---------------构造,状压dp

• 考虑m为零的情况,其实只要定义一种分配方案使得每种 k 都能被满足.那么,就是二进制. • 为每一个元素确定一个优先级,同时一个集合特征值定义为其中元素的最大优先级. • 可以发现特征值相同的元素一起被选择的话,一定是满足题目要求的.而且每种特征值所代表 集合的集合个数都恰好为各不相同的2的整数次幂.也就是说每个二进制数都可以被表示了. (即 k ) 然后就是确定优先级了: 记??[??]表示集合S 里的元素已经被分配了最高的若干优先级,是否可行转移时枚举接下来的优先级最高的元素是哪个. *

Joseph Problem(详细解法)

前言 这几天学习了队列,于是尝试了一下Joseph Problem,然后一直有一个地方没有通过,终于经点拨后,通过了.对于队列的使用还是加深了印象.建议如果队列的练手可以去尝试解决这个问题. 正文 Joseph Problem(35分) 铺垫: 假设有N个人围成一圈,然后第一个人把第二个人杀了,刀子给第三个人,第三个人把第四个人杀了,以此类推...... 首先注意:难点1:围成一圈,我们会想用什么数据结构呢?这么多人,首先应该想到用数组对不对,可是怎么表示围成一圈呢?重点来了,其实我们可以不断的

有两杯,一个11L一个7L,水任用,得到2L 的详细解法

问题:有两个水杯,一个是11L一个是7L,水可以随便用,怎么得到2L 1.了解问题的本质 问题中给出了两个杯子,只有这两个杯子有量度,所以只能让杯中的水满进满出才能确定杯子中最后有多少水. 现在问题要求通过两个杯子中水的倒进倒出,最后正好多出2L. 我们不难想到,想要得到这2L,有两种方式: 1>给11L装满,然后倒进7L,然后剩下的倒进7L,再给11L倒满……(简单说:从11L满进,从7L满出) 2>给7L装满,然后倒进11L,然后剩下的倒进11L,再给7L倒满……(简单说:从7L满进,从1