BZOJ3181: [Coci2012]BROJ
3181: [Coci2012]BROJ
Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 137 Solved: 47
[Submit][Status][Discuss]
Description
求最小质因子等于p的第n小的正整数(恰好有n-1个最小质因子等于p且比它
小的正整数)。p一定是质数。若答案超过10^9则输出0。
Input
Output
Sample Input
2 3
Sample Output
9
HINT
1 <= n, p <= 10^9
Source
题解:论文题,感觉最近看的几篇论文,感觉就是告诉我们一个思想,就是分而治之
我们对于一个问题,划分为两个子问题,用他们自己所特有的特性,求出答案
时间复杂度能优化许多
例如这道题:
我们要求的是:{x|x的最小质因子为p}中的第k小
我们考虑转化:{vp|vp<1e9 && v的质因子都不小于p}中的第k小
于是问题获得转化由求x-->x/p
我们又可以考虑x/p与p呈反比例关系,是不是对于不同的p,我们可以利用其中较小的那个来求答案?
考虑p比较大,v比较小,我们可以暴力求出v的第k小
考虑p比较大,v比较大,的情况,我们考虑问题怎么转化:
问题可以转化为:
考虑将枚举质因子(非最小),对于含有一个质因子的数的集合,我们可以利用容斥来求出质因子<p集合的并
于是问题转化为:
实际和理论证明,分界线取61--67最优!
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<iostream> #include<algorithm> #include<cstring> #include<cstdio> #include<cmath> #define ll long long #define inf 1000000000 #define N 1000000000/66 using namespace std; int n,m,pri[105],tot; bool v[N]; int read() { int x=0,f=1; char ch; while (ch=getchar(),ch<'0'||ch>'9') if (ch=='-') f=-1; while (x=x*10+ch-'0',ch=getchar(),ch>='0'&&ch<='9'); return x*f; } int check(int n,int m){ tot=0; for (int i=2; i<=m; i++) v[i]=0; ll z=n; for (int i=2; i<m; i++) { if (!v[i]) { pri[tot++]=i;} for (int j=0; j<tot && 1ll*pri[j]*i<=m; j++) { v[i*pri[j]]=1; if (i%pri[j]==0) break; } } for (int i=1; i<(1<<tot); i++) { ll d=1; int f=-1; for (int j=0; j<tot; j++) if (i&(1<<j)){ d=d*pri[j]; if (d>n) break; f=-f; } z-=(ll)f*n/d; } //cout<<" "<<z<<" "<<n<<endl; return z; } int work1(int n,int m){ int l=2,r=inf/m; while (l<r){ int mid=(l+r)>>1; if (check(mid,m)<n) l=mid+1; else r=mid; } //cout<<" "<<r<<endl; return check(l,m)==n?l*m:0; } int work2(int n,int m){ if (n==1) return m; for (int i=2; i<inf/m; i++) v[i]=0; int cnt=1; for (int i=2; i<inf/m; i++) if (!v[i]){ if (i<m) for (ll j=(ll)i*i; j<=inf/m; j+=i) v[j]=1; else if (++cnt==n) return i*m; } return 0; } int main() { while (~scanf("%d%d",&n,&m)){ printf("%d\n",m<=65?work1(n,m):work2(n,m)); } return 0; }
我太蒟蒻了,所以神犇们留下意见让我跪膜