zoukankan      html  css  js  c++  java
  • 【数学】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 }    
  • 相关阅读:
    修改sqlserver2008中表的schema
    MongoDB学习笔记06
    MongoDB学习笔记05
    MongoDB学习笔记04
    在IIS Express中调试时无法读取配置文件
    Spring 集成Redis
    Java操作Redis(代码演示)
    Redis的一些常用命令操作
    Redis安装步骤
    如何彻底删除电脑安装的软件程序?
  • 原文地址:https://www.cnblogs.com/L-Excalibur/p/8559352.html
Copyright © 2011-2022 走看看