zoukankan      html  css  js  c++  java
  • 【noi 2.7_413】Calling Extraterrestrial Intelligence Again(算法效率--线性筛素数+二分+测时)

    题意:给3个数M,A,B,求两个质数P,Q。使其满足P*Q<=M且A/B<=P/Q<=1,并使P*Q最大。输入若干行以0,0,0结尾。

    解法:先线性筛出素数表,再枚举出P,二分出对应的最大的Q,得出最佳答案。

    注意——1.第二个的代码是标准的欧拉筛,可求每个数的最小质因数;  2. 像第一个代码二分时通过位运算,使pri[]的下标尽量大来实现,比一般的二分快了很多很多!!一个6ms,一个502ms。具体请见代码。

     1 #include<cstdio>
     2 #include<cstdlib>
     3 #include<cstring>
     4 #include<iostream>
     5 using namespace std;
     6 #define M 100010
     7 #define D 1010
     8 
     9 bool np[M/10];
    10 int pri[M/20];
    11 int cnt;
    12 
    13 int mmin(int x,int y) {return x<y?x:y;}
    14 void init_pri()
    15 {
    16     cnt=0;
    17     memset(np,false,sizeof(np));
    18     for (int i=2;i<=M/10;i++)
    19     {
    20       if (!np[i]) pri[++cnt]=i;
    21       for (int j=1;j<=cnt&&i*pri[j]<=M/10;j++)
    22       {
    23         np[i*pri[j]]=true;
    24         if (i%pri[j]==0) break;//不能调到前一句前
    25       }
    26     }
    27     /*2
    28     cnt=0;
    29     memset(np,false,sizeof(np));
    30     for (int i=2;i<=M/10;i++)
    31     {
    32       if (np[i]) continue;
    33       pri[++cnt]=i;
    34       for (int j=2;i*j<=M/10;j++)
    35         np[i*j]=true;
    36     }
    37     */
    38 }
    39 int main()
    40 {
    41     init_pri();
    42     while (1)
    43     {
    44       int m,x,y;
    45       scanf("%d%d%d",&m,&x,&y);
    46       if (m+x+y==0) break;
    47       int pp,qq; pp=qq=0;
    48       for (int i=1;i<=cnt;i++)
    49       {
    50         int p=pri[i],lim=mmin(y*p/x,m/p);
    51         int tmp=i;
    52         for (int j=12;j>=0;j--)
    53           if (tmp+(1<<j)<=cnt && pri[tmp+(1<<j)]<=lim) tmp+=(1<<j);
    54         if (tmp==i && p*pri[tmp]>m) break;//上面的位调整没有一次成功,这时可能就单乘也是不合法的
    55         int q=pri[tmp];
    56         if (p*q>pp*qq) pp=p,qq=q;
    57       }
    58       printf("%d %d
    ",pp,qq);
    59     }
    60     return 0;
    61 }
    62
    Code1 快
     1 #include<cstdio>
     2 #include<cstdlib>
     3 #include<cstring>
     4 #include<iostream>
     5 using namespace std;
     6 #define M 100000
     7 #define N 1000
     8 typedef long long LL;
     9 
    10 int pr=0;
    11 LL mn_prim[M+10],prim[M+10];
    12 
    13 void get_prime()
    14 {
    15     memset(mn_prim,0,sizeof(mn_prim));//最小质因子
    16     for (LL i=2;i<=M;i++)
    17     {
    18       if (!mn_prim[i]) prim[++pr]=i;
    19       for (int j=1;j<=pr;j++)
    20       {
    21         if (prim[j]*i>M) break;
    22         mn_prim[prim[j]*i]=prim[j];
    23         if (i%prim[j]==0) break;//
    24       }
    25     }
    26 }
    27 int main()
    28 {
    29     LL m,a,b;
    30     get_prime();
    31     while (1)
    32     {
    33       scanf("%lld%lld%lld",&m,&a,&b);
    34       if (!m&&!a&&!b) break;
    35       LL tp=0,tq=0;
    36       for (int i=1;i<=pr;i++)
    37       {
    38         LL p,qq=0;
    39         p=prim[i];
    40         int l=i,r=pr;
    41         while (l<=r)
    42         {
    43           int mid=(l+r)>>1;
    44           LL q=prim[mid];
    45           if (p*q>m || a*q>b*p) r=mid-1;//相乘会超出int范围
    46           else qq=q,l=mid+1;
    47         }
    48         if (p*qq>tp*tq) tp=p,tq=qq;
    49       }
    50       printf("%lld %lld
    ",tp,tq);
    51     }
    52     return 0;
    53 }
    Code2 慢

    而关于线性筛素数,我有2种方法。第一种是每得到一个素数,就让它乘1、2、3...,得到的数标记为不是素数;第二种是最常见的,也是比较快的,每个数都与已得到的素数相乘,得到的数也标记为不是素数,但要小心:当这个数是当前枚举的素数的倍数时,就要跳出循环了。而语句的顺序在理论上为什么在后面,我就不清楚了...O.O

  • 相关阅读:
    JS判断单选框是否选中
    Js判断是否有属性
    判断是否有焦点
    Js 替代
    Js解析json
    回车事件
    js解析XML
    Linux常用基础(三)
    Linux常用基础(二)
    Linux常用基础(一)
  • 原文地址:https://www.cnblogs.com/konjak/p/6013713.html
Copyright © 2011-2022 走看看