「BZOJ 3181」 [Coci2012]BROJ

求最小质因子等于 p 的第 n 小的正整数。 p 一定是质数。若答案超过 10 9 则输出 0 。( 1 n , q 10 9 )

论文题。
《2014信息学奥林匹克中国国家队候选队员论文——寻找k优解的几种方法》,俞鼎力。
《2014信息学奥林匹克中国国家队候选队员论文——寻找k优解的几种方法》,俞鼎力

#include <cstdio>
#include <cstring>
#define R register
int P[966218], tot, n, p, vis[14925393], cnt;
namespace Part1
{
    int pos, cnt;
    void main()
    {
        R int lim = 1e9 / p;
        for(R int i = 2; i <= lim; ++i)
        {
            if(!vis[i])
            {   
                P[++tot] = i; 
                vis[i] = i;
            }
            for(R int j = 1; P[j] * i <= lim; ++j)
            {
                vis[i * P[j]] = P[j];
                if(i % P[j] == 0) break;
            }
        }
        --n;
        if(n == 0){ printf("%d\n", p); return ; }
        for(R int i = 2; i <= lim; ++i) 
            if(vis[i] >= p && !--n){ printf("%d\n", i * p); return ; } 
        puts("0");
    }
}
namespace Part2
{
    int f[1 << 17];
    void main()
    {
        for(R int i = 2; i < p; ++i)
        {
            if(!vis[i]) P[tot++] = i; 
            for(R int j = 0; P[j] * i < p; ++j)
            {
                vis[i * P[j]] = 1;
                if(i % P[j] == 0) break;
            }
        }
        R int Full = 1 << tot;
        for(R int i = 0; i < Full; ++i)
        {
            f[i] = p;
            R bool flag = 0;
            for(R int j = 0; j < tot; ++j) if(i >> j & 1) flag ^= 1;
            for(R int j = 0; j < tot; ++j) if(i >> j & 1)
            {
                if(1ll * f[i] * P[j] > 1000000000)
                {
                    f[i] = 2147483647;
                    break;
                }
                f[i] *= P[j];
            }
            if(flag) f[i] = -f[i];
        }
        R int l = -10, r = 1e9 + 10;
        while(r - l > 1)
        {
            R int mid = l + r >> 1;
            R long long Ans = 0;
            for(R int i = 0; i < Full; ++i) Ans += mid / f[i];
            if(Ans >= n) r = mid;
            else l = mid;
        }
        if(r > 1e9) puts("0");
        else printf("%d\n", r);
    }
}
int main()
{
    scanf("%d %d", &n, &p);
    if(p >= 67) Part1::main();
    else Part2::main();
    return 0;
}

猜你喜欢

转载自blog.csdn.net/steaunk/article/details/80088328