1986: 【COCI11-12 #4】纠结的数
时间限制: 1 Sec 内存限制: 128 MB题目描述
找出第N小的正整数X,满足条件X的最小的素因子是P。如果X的值超过10^9,则输出0。
输入
第1行:2个整数N和P (1 ≤ N, P ≤ 10^9),P一定是素数
输出
第1行:满足条件的数X或者0
样例输入
2 3
样例输出
9
这道题对p进行讨论,当p>=50时枚举打标记可过,
当p < 50时,二分rt,Ans = rt * p,
容斥去求能被p整除但不能被小于p的素数整除的数的个数,看是不是第N个
这题的容斥用循环,(1 << cnt)的二进制数位表示各个素数是否选中的情况,然后根据当前的交集个数来确定正负号
想了想还是要给出两个版本,一个 for 的容斥和一个 Dfs 版的容斥
Code:
For版(这是笔者的):
#include<iostream>
#include<cstdio>
using namespace std;
typedef long long LL;
const int MAX = 1000000000;
int N, P, Ans, cnt;
int prime[10005];
void Get_Prime(){
static bool flg[100005];
for(int i = 2; i < P; ++ i){
if(! flg[i]) prime[++ cnt] = i;
for(int j = i * i; j <= P; j += i)
flg[j] = 1;
}
}
bool check(int x){
int sign, pro, tot = x;
for(int i = 1; i < (1 << cnt); ++ i){
sign = pro= 1;
for(int j = 1; j <= cnt; ++ j)
if(i & (1 << (j - 1))){
pro *= prime[j];
if(pro > x) break;
sign *= -1;
}
tot += x / pro * sign;
}
return tot >= N;
}
void Work(){
if(N == 1){
Ans = P;
return ;
}
if(P * P < 0 || P * P > MAX){
Ans = 0;
return ;
}
Get_Prime();
if(P < 50){
int l = 1, r = MAX / P, mid, rt = 0;
while(l <= r){
mid = (l + r) >> 1;
if(check(mid))
rt = mid, r = mid - 1;
else l = mid + 1;
}
if(! rt) Ans = 0;
else Ans = rt * P;
}
else {
static bool Flg[MAX / 50 + 5];
int tot = 0, mx = MAX / P;
for(int i = 1; i <= cnt; ++ i)
for(int j = prime[i]; j <= mx; j += prime[i])
Flg[j] = 1;
for(int i = 1; i <= mx; ++ i) if(! Flg[i]){
++ tot;
if(tot == N){
Ans = P * i;
return ;
}
}
}
}
int main(){
scanf("%d%d", &N, &P);
Work();
printf("%d\n", Ans);
return 0;
}
Dfs版(这是笔者损友的,速度更优):
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
const int Max=1e9;
using namespace std;
int n,p;
int gcd(int a,int b){
return !b?a:gcd(b,a%b);
}
int lcm(int a,int b){
return a*b/gcd(a,b);
}
int prime[10005],cnt;
void sieve(int P){
static bool flag[100005];
for(int i = 2; i < P; ++ i){
if(! flag[i]) prime[++ cnt] = i;
for(int j = i * i; j <= P; j += i)
flag[j] = 1;
}
}
int a,b;
void dfs(int i,int data,int flag,int &ans){
if(i>cnt)
{
if(flag&1) ans+=b/data;
else ans-=b/data;
}
else
{
dfs(i+1,lcm(data,prime[i]),flag+1,ans);
dfs(i+1,data,flag,ans);
}
}
bool judge(int x){
b=x*p;
int ans=0;
dfs(1,p,1,ans);
return ans>=n;
}
int work(){
if(n==1) return p;
if(p * p < 0 || p * p > Max)
return 0;
sieve(p);
if(p<50)
{
int l=1,r=Max/p,mid,rt=0;
while(l<=r)
{
mid=(l+r)>>1;
if(judge(mid)) rt=mid,r=mid-1;
else l=mid+1;
}
if(rt)
return p*rt;
else return 0;
}
else
{
static bool vis[Max/50+5];
int up=Max/p;
for(int i=1;i<=cnt;i++)
for(int j=prime[i];j<=up;j+=prime[i])
vis[j]=1;
int i, tot = 0;
for(i=1;i<=up;i++)
{
if(!vis[i]) ++ tot;
if(tot==n) return p*i;
}
return 0;
}
}
int main()
{
scanf("%d%d",&n,&p);
printf("%d",work());
}