codeforces 470 Primal Sport

题意

给定一个数x0,取小于x0的任何一个素数p1。将这个素数扩大到n1倍,使其恰好大于等于x0。然后将扩大后的这个数也就是n1*p1设置为x1。同样的操作,任取一个小于x1的素数p2。将其扩大到n2倍使得他刚好大于等于x1。设这个扩大到n2倍的数设为x2。现在告诉你x2的值,让你输出最小的可能的x0

分析

我们将上面的 叙述用数学表达式写出来就是
p1 < x0 <= p1*n1 = x1;   p2 < x1 <= p2*n2 = x2;
然后还有一个条件恰好大于等于。也就是说x1-p1就要小于x2。那么我们又可以进一步缩进x2的范围也就是
x2-p2+1 <= x1 <= x2 同理也有 x1-p1+1 <= x0 <= x1
从第一个不等式可以看到,x1的范围是由p2也就是第二次选出的那个素数所决定的,那我们想x0小那x1也要尽量小。所以我们从他可能的最小值x2-p2+1开始遍历一直到x2。注意这里的p2选的是x2的最大素数因数。在这次遍历中我们已经定下来 x1了,那接下来的问题就是如何用x1来确定x0的最小值。
  同理x2推x1的道理,x0的范围也是[x1-p1+1,x1]。很显然此时x0最小肯定是x1-p1+1,这个p1也是x1的最大素数因数。
  找到x1和x2的最大素数因数的算法比较巧妙。大体的思路类似于筛选法求素数,设定一个f数组表示的是f[i]表示的是i这个数的最大素数因数。首先定位0,然后从2开始筛选一次所有非素数,也就是不断的加2。那很显然2肯定是被筛选的数的因子且是素数。然后找下一个素数,找法是利用构造的f数组。素数不可能是除1和本身以外的数的因素。所以在f列表里面素数肯定是没有被初始化的也就是0。
先贴出来。

void getp()
{
    int n = 2;
    while (n < maxn)
    {
        //num表示的是当前刷新的数,因为一开始的肯定是素数,而下一个刷新的值直接是加n所以直接赋给2*n
        int num = n*2;
        //用n遍历一遍刷新所有的素数因数的值
        while (num < maxn)
        {
            f[num] = n;
            num += n;
        }
        //找下一个素数
        num = n + 1;
        while (f[num] != 0 && n < maxn)
        {
            num++;
        }
        //找到了赋值给n
        n = num;
    }
}

完整代码

#include <iostream>
#include <cmath>
#define mina(a,b) a<b?a:b
#define maxn 1000005
using namespace std;

int f[maxn];
void getp()
{
    int n = 2;
    while (n < maxn)
    {
        int num = n*2;
        while (num < maxn)
        {
            f[num] = n;
            num += n;
        }
        num = n + 1;
        while (f[num] != 0 && n < maxn)
        {
            num++;
        }
        n = num;
    }
}

int main()
{
    getp();
    int x2;
    while (cin >> x2)
    {
        int p2 = f[x2];
        int x0 = 999999;
        int p1 = 0;
        for (int i = x2 - p2 + 1; i <= x2; i++)
        {
            p1 = f[i];
            x0 = mina((i - p1 + 1), x0);
        }
        cout << x0 << endl;
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/cugsl/article/details/79629110