codeforces 948B Primal Sport

开启传送门

Alice and Bob begin their day with a quick game. They first choose a starting number X0 ≥ 3 and try to reach one million by the process described below.

Alice goes first and then they take alternating turns. In the i-th turn, the player whose turn it is selects a prime number smaller than the current number, and announces the smallest multiple of this prime number that is not smaller than the current number.

Formally, he or she selects a prime p < Xi - 1 and then finds the minimum Xi ≥ Xi - 1 such that p divides Xi. Note that if the selected prime p already divides Xi - 1, then the number does not change.

Eve has witnessed the state of the game after two turns. Given X2, help her determine what is the smallest possible starting number X0. Note that the players don't necessarily play optimally. You should consider all possible game evolutions.

Input

The input contains a single integer X2 (4 ≤ X2 ≤ 106). It is guaranteed that the integer X2 is composite, that is, is not prime.

Output

Output a single integer — the minimum possible X0.

Examples
Input

14

Output

6

Input

20

Output

15

Input

8192

Output

8191

Note

In the first test, the smallest possible starting number is X0 = 6. One possible course of the game is as follows:

    Alice picks prime 5 and announces X1 = 10
    Bob picks prime 7 and announces X2 = 14. 

In the second case, let X0 = 15.

    Alice picks prime 2 and announces X1 = 16
    Bob picks prime 5 and announces X2 = 20. 

【题意】

两个人玩游戏,游戏规则如下:

1,有一个初始值 X 0
2,每个操作者面对 X i 时,选择任意一个比 X i 小的质数,然后乘上一个最小的倍数,使得 p r i m e x >= X i
3,用这个对应的 p r i m e x 来更新 X i + 1

现在告诉你两个人玩的时候产生的 X 2 ,问你最小的可能的 X 0 .

【分析】

其实仔细想想还是很简单的。

我们这里选择倒推。如果我们知道了 X 1 怎么求 X 0 呢?

给出一个比较明显的结论:

如果 X i 可以写成 X i = p r i m e x 的形式,那么 X i 1 的可能区域是[ X i p r i m e + 1 , X i ]。

上面的结论很容易证明,因为对于上面区间的每一个数来说,我都选择对应的那个prime,为了保证 p r i m e x > X i ,那么显然有 p r i m e x == X i 。命题得证。

继续刚刚的问题:如果我们知道了 X 1 怎么求 X 0 呢?

由刚刚的结论我们可以得到一个比较容易的做法是,我们枚举prime,可以得到每个 X 1 的最小前驱是谁,也就是对应的 X 0 .这个东西我们可以预处理出来。那么现在的问题就是如何根据 X 2 得到 X 1 .

其实这个问题也不难。

我们得到了 X 2 ,我们就可以枚举每一个 X 2 的质因子。因为 X 2 肯定是 p r i m e x 的形式,所以我们可以得到的是

X 1 [ X 2 p r i m e + 1 , X 2 ]

这样枚举 X 2 的每一个质因子我们可以得到一个 X 1 的一个个区间,那么答案显然就是所有这些 X 1 的前驱的最小值。注意到我们预处理了每一个前驱,所以现在我们只用将刚刚预处理的数组初始化成一个线段树,然后对于每个区间我们区间查找一下,找到最小解就是答案。

【代码】

#include <bits/stdc++.h>
using namespace std;
const int maxm = 1e6+10;
bool p[maxm];
int pri[maxm];
void init(){///质数表
    for(int i = 2;i<maxm;i++){
        if(!p[i]){
            pri[++pri[0]] = i;
            for(int j = i*2;j<maxm;j+=i) p[j] = true;
        }
    }
}
int pre[maxm];///统计前驱
int tree[maxm<<2];///线段树维护区间最小值
void build(int ind = 1,int l = 2,int r = maxm-1){
    if(l==r) tree[ind] = pre[l];
    else{
        int mid = (l+r)>>1;
        build(ind<<1,l,mid);
        build(ind<<1|1,mid+1,r);
        tree[ind] = min(tree[ind<<1],tree[ind<<1|1]);
    }
}
int cal(int l,int r,int ind = 1,int ll = 2,int rr = maxm-1){///询问区间最小值
    if(l<=ll&&rr<=r) return tree[ind];
    int mid = (ll+rr)>>1;
    if(l>mid) return cal(l,r,ind<<1|1,mid+1,rr);
    else if(r<=mid) return cal(l,r,ind<<1,ll,mid);
    else{
        return min(cal(l,mid,ind<<1,ll,mid),
                   cal(mid+1,r,ind<<1|1,mid+1,rr));

    }
}
int main(){
    //freopen("C:\\Users\\ACM2018\\Desktop\\in.txt","r",stdin);
    init();
    memset(pre,0x3f3f,sizeof(pre));
    for(int i = 1;i<=pri[0];i++){
        for(int j = pri[i]*2;j<maxm;j+=pri[i]){///暴力找到每个数据的前驱
            pre[j] = min(pre[j],j-pri[i]+1);
        }
    }
    build();///建树
    int ans = maxm;
    int a;
    scanf("%d",&a);
    for(int i = 1;i<=pri[0]&&a>pri[i];i++){
        if(a%pri[i]==0){
            ans = min(ans,cal(a-pri[i]+1,a));
        }
    }
    printf("%d\n",ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/mengzhongsharen/article/details/80136592