【数学】Codeforces Round #470 (Div2) B

题目链接:http://codeforces.com/contest/948/problem/B

 

题目大意:有一个大于等于3的数X0,任意选择一个小于X0的质数P0,乘以一个数k使k*P0>=X0,且(k-1)*P0<X0,令X1=k*P0,任意选择一个小于X1的质数P1,乘以一个数u使u*P1>=X1,且(u-1)*P1<X1,令X2=u*P1;现在给你X2,求出所有满足条件的X0里最小的那一个。

 

解题思路:

绕,超级绕。

我一开始读题目的时候就觉得这道题很绕完全搞不清楚大小关系,经过神级学长的耐心讲解终于搞懂了,此处%红太阳。

首先我想到的是暴力解法,枚举出所有的X1,再枚举出X1最大的质因数,X1-P+1的最小值即为解。于是我们来算一下时间复杂度。枚举所有的X1->O(n),枚举出X1最大的质因数->O(sqrt(n)),n的范围在1e6,果断T。

于是寻找更省时间的方法,不用枚举X1或者不用枚举X1的质因数。

我们探究一下X1和X2的关系,发现如果从X2着手,是可以确定X1的范围的。X2等于一个小于等于X1的质数乘以一个正数,不妨设这个质数为P,那么X2-P<X1<=X2,右区间是固定死了的X2,左区间的最小值在P取最大值的时候取到。所以X1的范围是[X2-X2最大的质因数+1,X2]。

似乎没有什么用,还是要枚举,但是如果我们已知了X0呢?

假设我们有一个满足条件的X0,一定可以找到一个X1>=X0且处于这个区间(因为保证了X0是满足条件的一个解)。这个X1是如何找到的?一个小于等于X0的质数乘以一个正数!也就是说,对于任意大于X0且小于等于X2的数X0',这个质数都存在,那么这个X1也存在,那么当X1>=X0'的时候,我们X0‘也是合理解,当X1<X0'的时候,X0’必定处于这个区间!(X1处于这个区间,X0'小于等于X2)。而处于这个区间的所有数都是一个满足条件的X0(可以取自己的质因数乘以一个因子等于自己,那么X0==X1,X1处于区间内)。

于是我们得出结论:只要一个X0是满足条件的解,所有大于X0且小于等于X2的都是满足条件的解。

满足单调性->求最小->二分!

最后只要二分X0即可。

下面放31msAC代码:

 1 #include<stdio.h>
 2 #define MAXN 1000000
 3 
 4 int prime[MAXN+5],tot;
 5 bool f[MAXN+5];
 6 
 7 int _max(int a,int b){return a>b?a:b;}
 8 
 9 void _before(){
10     
11     int i,j;
12     for(i=2;i<=MAXN;i++){
13         if(!f[i])prime[++tot]=i;
14         for(j=1;j<=tot&&prime[j]*i<=MAXN;j++){
15             f[i*prime[j]]=true;
16             if(i%prime[j]==0)break;
17         }
18     }
19 }
20 
21 int main(){
22     
23     int x1,x2,l,r,i,mid,p;
24     bool flag;
25     _before();
26     scanf("%d",&x2);
27     if(!f[x2]){
28         printf("%d",x2);
29         return 0;
30     }
31     for(i=tot;i>=1;i--)
32         if(x2%prime[i]==0)break;
33     p=prime[i];
34     l=2; r=x2;
35     while(l<r){
36         if(l+1==r)break;
37         mid=(l+r)>>1;
38         flag=false;
39         for(i=1;prime[i]<=mid;i++){
40             x1=(_max(mid,x2-p+1)+prime[i]-1)/prime[i]*prime[i];//取大于左端点的最小的数
41             if(x1-prime[i]<mid&&x1<=x2){
42                 flag=true;
43                 break;
44             }
45         }
46         if(flag)r=mid;
47         else l=mid;
48     }
49     printf("%d",r);
50     return 0;
51 }    

 

转载于:https://www.cnblogs.com/L-Excalibur/p/8559352.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值