51Nod3236-第k小生成数
0.题目大意
给定三个正整数m,n,k(2≤m≤1e7,1≤k≤n≤5e7)。已知一个长度为n的序列a满足(mod为题目给出的常数,为1e9+7),求a中第k小的数字。
(注意,本序列从开始,即)
1.分析题目
①初步分析
首先,开一个大小为5e7的整形数组再排序是不现实的。题目的内存上限是313072KB,而一个大小为5e7的整形数组所占用的内存为195312.5KB。显然,MLE了。
同时,n的上限是5e7,而时限为1.5s。这说明什么?这说明只能用O(n)的算法通过。甚至连常数打了都不行。虽然题目的标签有一个基数排序,但是实际上这道题不能直接使用基排。(你想想,不仅不能使用数组存储数字;而且基排的常数是比较大的,不能保证卡过时限)
②打开思路
那能怎么办?如果你的思路是比较开阔的,你应该想到一道类似的题目:给出一个数组,求第k小的数字。那题数据很小,所以使用各种方法都能过。而其中最正统的写法就是运用了快排的思想:
每次选择一个“哨兵”,大于它的数字排在它左边,小于它的数字在它的右边。计算两边的元素个数,可以缩小第k小数字的范围。
但是,这个算法有一个缺点:其最优的时间复杂度为O(n),可是但凡你的运气差一点,就很可能导致两边的数字个数相差甚远。比如,你运气奇差或者题目数据有些变态,导致你每次选中的哨兵都是当前序列中的最大或最小值,那么该算法就会退化至。这是不能接受的。
所以,我们要使用另一种思路:因为这些数字的值域都很小,所以我们大可以使用一个bool数组来记录数字i是否在序列中出现过。再求一个前缀和,这题目就能轻松搞定了。
这个思路是可以借鉴的。但是在本题中, 的理论最大值为mod-1,即1e9+6。这个数字还是太大了——5e7的数组都存不下,更何况1e9呢!思路进入了死胡同。
但是,这个“死胡同”中,并非无路可走:既然1e9的数组存不下,那我就把数字分为两部分——低五位(即个位、十位、百位、千位、万位)与高五位(十万、百万、千万、亿、十亿)。只要我们能求出第k小数字的高五位与低五位,问题就能得到解决。因为高五位的权值更大,所以我们先处理高五位,求出第k小的数字的高五位是多少。再求低五位,就能轻松搞定了。
2.最终代码
①Q:但是,我们怎么求每个数字的高五位与低五位呢?
A:(精华在于注释,下同)
const int mod = 1e9 + 7, num = 1e5;
int m, n, k;
int cnt[num + 1];
cin>>m>>n>>k;
int last = 1, x, h; //h是前面5位
cnt[last/num+1]++;
for (int i = 2; i <= n; i++) {long long now=1ll*x*lastnow%=mod;x=now;cnt[x / num + 1]++; //注意,这里有一个加一,为了方便cnt[0]的处理last = x;
}
②Q:我们怎么存储个数呢?
A:
int cnt[num + 10];//cnt[i]表示值为i的个数出现的次数
③Q:我们怎么确定第k小数字的前五位呢?
A:
for (int i = 1; i <= num; i++) {cnt[i] += cnt[i - 1];if (cnt[i] >= k) {h = i - 1;//h表示第k小数字的高五位。-1是因为处理cnt[0]时会数组越界,就整体都加1k -= cnt[i - 1];//这一步不能忘。因为第一轮筛选过后k对于高五位为i的数字内部来说k应该减去cnt[i-1]break;}
}
④ Q:我悟了……
A:悟了就好,自己写完之后来核对一下代码或者自己直接交。
#include<iostream>//有缘千里来相见,万年不变头文件
#include<stdio.h>
#define int long long//十年OI一场空,不开long long见祖宗
using namespace std;
const int mod = 1e9 + 7, num = 1e5;//酒逢知己千杯少,定义常量莫忘了
int m, n, k;
int cnt[num + 1];
signed main() {scanf("%lld%lld%lld",&m,&n,&k);int last = 1, x, h;cnt[last/num+1]++;for (int i = 2; i <= n; i++) {x = last * m % mod;//这里开了long long,就不用担心爆int了cnt[x / num + 1]++; last = x;}for (int i = 1; i <= num; i++) {cnt[i] += cnt[i - 1];if (cnt[i] >= k) {h = i - 1;k -= cnt[i - 1];break;}}
// printf("h:%lld k:%lld\n",h,k);for (int i = 0; i <= num; i++) {cnt[i] = 0;}last = 1;if(last/num==h) cnt[last%num+1]++;for (int i = 2; i <= n; i++) {x = last * m % mod;if(x/num==h)cnt[x%num+1]++;last = x;}for(int i=1;i<=num;i++){cnt[i]+=cnt[i-1];if(cnt[i]>=k){int answer=h*num+i-1;printf("%lld",answer);return 0;}}
}
完结撒花!
51Nod3236-第k小生成数相关推荐
- 次小生成树(Prim + Kruaskal)
问题引入: 我们先来回想一下生成树是如何定义的,生成树就是用n - 1条边将图中的所有n个顶点都连通为一个连通分量,这样的边连成子树称为生成树. 最小生成树很明显就是生成树中权值最小的生成树,那么我们 ...
- ACM题目————次小生成树
Description 最小生成树大家都已经很了解,次小生成树就是图中构成的树的权值和第二小的树,此值也可能等于最小生成树的权值和,你的任务就是设计一个算法计算图的最小生成树. Input 存在多组数 ...
- 【数据结构与算法】【算法思想】贪心算法
贪心算法 回溯算法 分治算法 动态规划 四种基本的算法思想:贪心算法,分治算法,回溯算法,动态规划,他们不是具体算法,常用来指导我们设计具体的算法和编码等. 一:贪心算法有很多经典应用 霍夫曼编码(H ...
- 现代图论笔记(二)树与二分图
写在前面 这次介绍一些树和二分图的定义和主要性质, 以及这两种结构中常用的算法, 包括二分图的判定, 最小生成树的寻找等. 好久才更新, 只能说自己的代码能力还有欠缺, 一些算法知道思路但就是写不出来 ...
- 最小生成树prim、
过年那几天确实没好好学习.在老家闲着也是闲着.可是就是没看书. 回来这几天又一直在弄个人博客.买域名云服务器备案什么的- -. 麻烦死了呢. 在腾讯花1块钱备案了一个网站www.goodgoodstu ...
- MangataのACM模板
文章目录 数据结构 并查集 树状数组 二维单点修改,区间查询 二维区间修改,单点查询 二维区间修改,区间查询 线段树 单点修改,区间查询 区间更新.区间查询 主席树(区间第k小数模板) 单调栈 单调队 ...
- The 2021 ICPC Asia Regionals Online Contest (I)
The 2021 ICPC Asia Regionals Online Contest (I) 写了一晚上,日- 文章目录 一. A Busiest Computing Nodes 二.D Edge ...
- [树上倍增][最小生成树]JZOJ P4313——电话线铺设
Description Input Output Sample Input 6 9 4 6 3 4 2 5 6 5 4 6 1 3 5 3 5 9 5 6 8 4 1 5 4 6 4 6 2 7 2 ...
- 两种构造最小生成树的算法(普里姆算法,克鲁斯卡尔算法)
(一)普里姆算法 普里姆算法求最小生成树:从生成树中只有一个顶点开始,到定点全部进入生成数为止: 2.克鲁斯卡尔算法. 思想:将所有边按其权值从小到大排一遍,从小到大依次选取边,加入最小生成树中,若加 ...
最新文章
- sscanf操作字符串和整型的区别
- java字符串转化为数组_Go 语言字符串和数组转化 | 臭大佬
- 使用 CORBA 和 Java IDL
- java oca_OCA第2部分中的Java难题
- 有关java的名句_关于志气的名言名句(精选50句)
- django-单表的增删改查-用户部门表
- VS2005常用插件
- 前端中台化,把格局做大:Node.js与测试服务探索
- 关于arcview 3.2 中输出图形添加坐标网格(Graticules and Measured Grids)时直接退出的问题...
- HTML+CSS个人简历练习
- 室内设计数据手册pdf_室内设计资料集pdf下载-室内设计资料集电子版pdf高清扫描版-东坡下载...
- LidarSLAM(一):NDT
- python图片转手绘_python图片转素描软件
- 学习笔记 -《量子计算与编程入门》- 量子程序
- 硬盘突然变raw格式_硬盘变成RAW格式怎么办
- USACO oct. 09 Watering Hole
- 超详细 | 贝叶斯网络基础——有图有真相
- swapidc的php语言,SWAPIDC目录说明及文件说明及某些常量内容
- 软件需求分析方法收集
- c语言金字塔输出乘法表,python中打印金字塔和九九乘法表的几种方法