找数
来源:互联网 发布:json对象合并成一个 编辑:程序博客网 时间:2024/05/10 18:09
题目大意及模型转换
找出第N个最小素因子是P的正整数。
N,P<=10^9,如果结果超过10^9则输出0否则输出这个数。
超过10^9
我们先来处理结果超过10^9。
显然,对于一个质数p,第一个符合条件的是自己,第二个就是p*p。
我们发现p<=10^9,也就是说,n=1的情况所有质数都不会超过10^9。
超过的情况会从第二个开始。
那么首先可以知道,对于大于
然而小于
不过现在,我们也就只需要考虑小于
分类讨论
设f[i]表示i含有的最大质因数,这个显然可以筛出来。
但因为空间限制,我们只能筛一部分。
对于质数p,如果找到一个q满足f[q]>=p,那么p*f[q]就是满足条件的数。
我们知道,对于大质数,很容易超过10^9。
如果我们规定一个界限,超过这个界限的质数去枚举q,那么q显然不会很大。
我们不妨设这个界限为200,那么q的最大值便为
这个空间不会爆,我们可以筛出来。
对于小质数,该怎么办呢?
二分查找
我们这样想,假设枚举出一个q。
我们想知道1~q中有多少个满足f值大于等于p的。
其实等价于总数减去f值小于p的。
如果最后得到的结果恰好为n,那么p*q即为第n个满足条件的。
这个q显然可以二分答案。
至于那个个数,没有那么简单。
我们的想法是减去2的倍数个数,3的倍数个数等等等等。
但是6的倍数会被算两次。
好我们加回来,又发现30的倍数多了等等等。
因此我们要用容斥原理。
用小于p的所有质数进行组合,选一些这样的质数组成一个x,那么看q以内有多少个数是x的倍数,接下来如果我们选择了奇数个质数组成x,就减,否则加。
深搜组合?复杂度好像很大。
但实际上,组合出来的必须在q以内,所以复杂度并不会很大。
注意
p*1也满足条件。第一种情况下,请记得特判。
二分结果后,还要进行验证来决定是输出答案还是输出0。
参考程序
#include<cstdio>#include<cmath>#define fo(i,a,b) for(i=a;i<=b;i++)#define fd(i,a,b) for(i=a;i>=b;i--)using namespace std;int f[5000000],pri[3000000],i,j,k,l,r,mid,t,n,p,m,w,top;long long xdl;void dfs(int x,int y,int z){ if (x==w){ if (y!=1){ if (z%2) t+=mid/y;else t-=mid/y; } return; } long long xdl=pri[x]*y; if (xdl<=mid) dfs(x+1,xdl,z+1); dfs(x+1,y,z);}int main(){ m=floor(sqrt(1000000000)); scanf("%d%d",&n,&p); if (p>m&&n>1) printf("0\n"); else if(p>m&&n==1) printf("%d\n",p); else if(n==1) printf("%d\n",p); else { fo(i,2,5000000){ if (!f[i]){ pri[++top]=i; f[i]=i; fo(j,i,5000000/i) if (!f[i*j]) f[i*j]=i; } } if (p>200){ n--; t=0; fo(i,2,5000000){ if (f[i]>=p){ t++; if (t==n){ xdl=p*i; if (xdl>1000000000) printf("0\n");else printf("%d\n",xdl); break; } } } } else{ fo(i,1,top) if (pri[i]==p) break; w=i; l=p; r=1000000000/p; while (l<r){ mid=(l+r)/2; t=0; dfs(1,1,0); if (mid-t<n) l=mid+1;else r=mid; } t=0; mid=l; dfs(1,1,0); if (l-t==n) printf("%d\n",l*p);else printf("0\n"); } }}
- 找数
- 找数
- 找数
- 找数
- 找数
- 找吸血鬼数(转)
- 找雷劈数
- C++找雷劈数
- 找重复数
- 圆盘找数
- 找丢失的数
- 找中间数问题
- 找最小数
- 找数-递归
- 找数算法笔记
- 找 完全数
- hdu5247 找连续数
- 【JZOJ】3188 找数
- C语言基础知识之(十三):指针、指针和数组
- 模拟淘宝侧边服务模块鼠标悬停效果的三种实现方式总结
- Alien Order
- Dataguard 重启方法
- CronSequenceGenerator
- 找数
- uImage,zimage,bzimage,vmlinux,vmlinuz
- Jetty JNDI开发实战(上)
- Python 列表学习与使用
- Ubuntu 10.04 速配指南
- C语言基础知识之(十四):指针和字符数组、字符串数组
- Unity3D有限状态机(FSM)学习笔记【3】FSState类
- static详解
- HDU 4458 Shoot the Airplane (2012年杭州赛区现场赛F题)