P2723 丑数 Humble Numbers

题目背景

对于一给定的素数集合 S = {p1, p2, ..., pK},考虑一个正整数集合,该集合中任一元素的质因数全部属于S。这个正整数集合包括,p1、p1*p2、p1*p1、p1*p2*p3...(还有其 它)。该集合被称为S集合的“丑数集合”。注意:我们认为1不是一个丑数。

题目描述

你的工作是对于输入的集合S去寻找“丑数集合”中的第N个“丑数”。所有答案可以用longint(32位整数)存储。

补充:丑数集合中每个数从小到大排列,每个丑数都是素数集合中的数的乘积,第N个“丑数”就是在能由素数集合中的数相乘得来的(包括它本身)第n小的数。

输入输出格式

输入格式:

第 1 行: 二个被空格分开的整数:K 和 N , 1<= K<=100 , 1<= N<=100,000.

第 2 行: K 个被空格分开的整数:集合S的元素

输出格式:

单独的一行,输出对于输入的S的第N个丑数。

输入输出样例

输入样例#1:

4 19
2 3 5 7
输出样例#1:

27

说明

题目翻译来自NOCOW。

USACO Training Section 3.1

我居然卡常卡过了!

嗯。。

一个方法是用二叉堆(非手写过不了的)

我们设第i个丑数是num[i]

我们用所有p去乘num[i],把它们压到栈里面。弹出最小数就是num[i + 1]

为了防止重加入的丑数重复需要判断一下

这题因为空间开小了交了很多遍才过

#include <bits/stdc++.h>
inline void read(long long &x){x = 0;char ch = getchar();while(ch > '9' || ch < '0'){ch = getchar();}while(ch >= '0' && ch <= '9')x = x * 10 + ch - '0', ch = getchar();}
inline long long max(long long a, long long b){return a > b ? a : b;}
inline long long min(long long a, long long b){return a > b ? b : a;}
inline void swap(long long &a, long long &b){long long tmp = a;a = b;b = tmp;}
const int INF = 0x3f3f3f3f;
const int MAXN = 100000 + 10;
const int MAXK = 200 + 10; long long p[MAXK],k,n;
long long heap[MAXN << 7];int cnt;
//小根堆
inline int down()//下滤
{
int rank = 1;
while(true)
{
int p;
if((rank << 1) > cnt)break;
if((rank << 1 | 1) > cnt)p = rank << 1;
else
{
if(heap[rank << 1] < heap[rank << 1 | 1])
p = (rank << 1);
else
p = (rank << 1 | 1);
}
if(heap[rank] >= heap[p])
{
swap(heap[rank], heap[p]);
rank = p;
}
else break;
}
}
inline void up(int rank)//上滤
{
while(heap[rank] < heap[rank >> 1] && rank > 1)
{
swap(heap[rank], heap[rank >> 1]);
rank >>= 1;
}
}
inline void insert(long long k)
{
heap[++cnt] = k;
up(cnt);
}
inline void del()
{
swap(heap[1], heap[cnt]);
cnt --;
down();
}
long long ans[MAXN];long long num; int main()
{
read(k);read(n);
for(int i = 1;i <= k;i ++)
{
read(p[i]);
}
heap[++cnt] = 1;
while(num <= n)
{
int tmp = heap[1];del();
if(ans[num] < tmp)
{
ans[++num] = tmp;
for(int i = 1;i <= k;i ++)
{
insert(tmp * p[i]);
}
}
}
printf("%lld", ans[n + 1]);
return 0;
}

另一种解法:

我们要找的ans[i] 要尽可能的接近ans[i - 1]

显然ans[i]是由素数集合p中某一个数与ans[j],j<i的乘积

证明:

令ans[i] = p[k] * M,k为任意数

如果M≠ans[j],则M  < ans[j]

那么M一定会被计入到前j个丑数中

矛盾

这样我们定义s[i]表示用素数i乘ans[s[i]]最接近ans[i - 1]的ans下标s[i]

可以得到i - 1时的s[k]  一定 小于等于i时的s[k],k取任意数

所以s[j]可以从i-1过继到i的,然后去递增直到满足   “s[i]表示用素数i乘ans[s[i]]最接近ans[i - 1]的ans下标s[i]”

#include <bits/stdc++.h>
inline void read(long long &x){x = 0;char ch = getchar();while(ch > '9' || ch < '0'){ch = getchar();}while(ch >= '0' && ch <= '9')x = x * 10 + ch - '0', ch = getchar();}
inline long long max(long long a, long long b){return a > b ? a : b;}
inline long long min(long long a, long long b){return a > b ? b : a;}
inline void swap(long long &a, long long &b){long long tmp = a;a = b;b = tmp;}
const long long INF = 0xfffffffffffffff;
const int MAXN = 1000000 + 10;
const int MAXK = 2000 + 10; long long k,n,p[MAXK],ans[MAXN],s[MAXK]; int main()
{
read(k);read(n);
for(int i = 1;i <= k;i ++){
read(p[i]);
}
ans[0] = 1;
for(int i = 1;i <= n;i ++)
{
ans[i] = INF;
for(int j = 1;j <= k;j ++)
{
while(p[j] * ans[s[j]] <= ans[i - 1])s[j] ++;
ans[i] = min(ans[i], p[j] * ans[s[j]]);
}
}
printf("%lld", ans[n]);
return 0;
}

最新文章

  1. EasyPR--中文开源车牌识别系统 开发详解(1)
  2. linux Centos 6.5 FTP服务原理及vsfptd的安装、配置(转)
  3. 转:C/C++中,空数组、空类、类中空数组的解析及其作用
  4. 在VMware中安装RHEL6.2(下)—— RHEL系统安装
  5. js对象与this指向
  6. Visual Studio 2013无法打开IIS Express Web的解决办法
  7. Linux下的简单好用的计算器bc
  8. Fix java version mismatch in windows---stackoverflow
  9. pygame写贪吃蛇
  10. Netty源码—四、事件处理
  11. Linux启动Redis失败/没有那个文件或目录
  12. 167. Two Sum II - Input array is sorted (Array)
  13. 【代码笔记】Web-ionic-安装及第一个app
  14. GitHub搭建个人网站详细教程
  15. Android ListView的使用(三)
  16. QQ名片自动点赞
  17. C++函数的高级特性
  18. SM2的非对称加解密java工具类
  19. 第一节 如何用Go实现单链表
  20. Ubuntu 配置多域名站点

热门文章

  1. c语言学习笔记 - 指针和字符串
  2. Jeecg-Boot前后端分离,针对敏感数据,加密传递方案
  3. 【转载】Python eval
  4. Dmarc指定外域邮箱接收报告
  5. elasticsearch query 和 filter 的区别
  6. mysql复制关系
  7. 未A,或用水法,或不熟的题
  8. HZOI2019 砍树 整除分块
  9. SQL Server数据库存储过程的异常处理
  10. 深入浅出 Java Concurrency (7): 锁机制 part 2 AQS[转]