bzoj3181: [Coci2012]BROJ
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cmath> 5 #include <algorithm> 6 using namespace std; 7 int n,p,top,list[105],bin[18],num[200005],ans,l,r,mid; 8 bool bo[15000005],vis[105]; 9 int lowbit(int x){return x&(-x);} 10 int work(int x,int y){ 11 long long fuckpps=1; 12 for (int i=1;i<=top;i++){ 13 if (x&bin[i-1]) fuckpps=fuckpps*list[i]; 14 if (fuckpps>1e9) return 0; 15 } 16 return y/fuckpps*(num[x]%2==0?1:-1); 17 } 18 bool check(int x){ 19 x/=p; 20 int sum=0; 21 for (int i=0;i<bin[top];i++){sum+=work(i,x);} 22 return sum>=n; 23 } 24 int main(){ 25 int x; 26 cin>>n>>p; 27 if (p>=69){ 28 x=1000000000/p; 29 memset(bo,1,sizeof(bo)); bo[1]=1; int cnt=1; 30 if (n==1){ 31 printf("%d\n",p); 32 return 0; 33 } 34 for (int i=2;i<=x;i++){ 35 if (bo[i]){ 36 if (i<p) for (long long j=1LL*i*i;j<=x;j+=i) bo[j]=0; 37 else{ 38 cnt++; if (cnt==n){printf("%d\n",i*p);return 0;} 39 } 40 } 41 } 42 if (cnt<n) puts("0"); 43 return 0; 44 } 45 top=0; memset(vis,0,sizeof(vis)); 46 for (int i=2;i<p;i++){ 47 if (!vis[i]){ 48 list[++top]=i; 49 } 50 for (int j=1;j<=top;j++){ 51 if (i*list[j]>=p) break; 52 vis[i*list[j]]=1; 53 if (i%list[j]==0) break; 54 } 55 } 56 bin[0]=1; for (int i=1;i<=top;i++) bin[i]=bin[i-1]<<1; 57 for (int i=1;i<bin[top];i++) num[i]=num[i-lowbit(i)]+1; 58 ans=0; l=1,r=1e9; 59 while (l<=r){ 60 mid=(l+r)>>1; 61 if (check(mid)) ans=mid,r=mid-1; 62 else l=mid+1; 63 } 64 printf("%d\n",ans); 65 return 0; 66 }
链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3181
题意:求最小质因子等于p的第n小的正整数(恰好有n-1个最小质因子等于p且比它
小的正整数)。p一定是质数。若答案超过10^9则输出0。
做法:当p>=69时,10^9/p可以接受线性算法,我们就找到1~10^9/p中最小质因子>=p的个数,我们可以用筛法实现,具体见代码,比较神奇。
当p<=61时,我们考虑二分答案x,然后容斥即可,复杂度为O(min(10^9/p,2^(小于p的质数个数)LogL))。