zoukankan      html  css  js  c++  java
  • BZOJ 1053 [HAOI2007]反素数ant

    53: [HAOI2007]反素数ant

    Description

      对于任何正整数x,其约数的个数记作g(x)。例如g(1)=1、g(6)=4。如果某个正整数x满足:g(x)>g(i) 0<i<x,则称x为反质数。例如,整数1,2,4,6等都是反质数。现在给定一个数N,你能求出不超过N的最大的反质数么

    Input

      一个数N(1<=N<=2,000,000,000)。

    Output

      不超过N的最大的反质数。

    Sample Input

    1000

    Sample Output

    840
      当我见到这道题的时候是很开心的,这不就是在东北育才当时我打表过70分的divisorful数吗?细细一想,会发现:
      一个合法的divisorful数x要求:0<i<x间存在至多一个数,其约数个数比x多。
       而一个合法的反质数x要求:0<i<x间不存在任何一个数,其约数个数比x多。
      我们可以想,对于一个divisorful数,一定是小因子占先。
      例如,6=2*3,约数个数为4。然而,437=19*23,也是4个。很明显不是。
      而这种题,如果打表,会发现整个divisorful数集其实极其稀疏。那么,我们就可以逐步加入各质因数p,让原divisorful数集中的数*p,*p^2,*p^3,*p^4……直到查询的边界。然后将其排序,去掉不合法的数。如果数集没有变化,就结束了。
      我们总结一下,这样的题满足:
    • 可以使用数集表示,数集本身较稀疏
    • 可以按合理的顺序逐步加入元素,并可贪心化break
    • 加入新元素时可以较快建立其维护信息
      啊啊啊啊啊!这样可以很快的求出2000000000内的所有反质数。挂个代码吧:
     1 /**************************************************************
     2     Problem: 1053
     3     User: Doggu
     4     Language: C++
     5     Result: Accepted
     6     Time:40 ms
     7     Memory:852 kb
     8 ****************************************************************/
     9  
    10 #include <cstdio>
    11 #include <algorithm>
    12 #include <vector>
    13 const long long MAX = 2500000000ll;
    14 typedef std::vector< std::pair<long long,int> > SET;
    15 SET v, w;
    16 int p, i, j, k;
    17 SET expand(SET &v,int p) {
    18     SET w=v;
    19     for( i = 0; i < v.size(); i++ ) {
    20         long long x=v[i].first*p;
    21         for( j = 1; x < MAX; x*=p,j++ ) w.push_back(std::make_pair(x,v[i].second*(j+1)));
    22     }
    23     sort(w.begin(),w.end());
    24     SET ans;
    25     int mx=-1;
    26     for( i = 0; i < w.size(); i++ ) {
    27         int c=w[i].second;
    28         if(c<=mx) continue;
    29         ans.push_back(w[i]);
    30         mx=w[i].second;
    31     }
    32     return ans;
    33 }
    34 int main() {
    35     v.push_back(std::make_pair(1,1));
    36     for( p = 2; ; p++ ) {
    37         bool pri=1;
    38         for( i = 2; i * i <= p; i++ ) if(p%i==0) {pri=0;break;}
    39         if(!pri) continue;
    40         w=expand(v,p);
    41         if(w==v) break;
    42         v=w;
    43     }
    44     scanf("%lld",&k);
    45     for( i = 0; i < v.size(); i++ ) if(v[i].first<=k&&v[i+1].first>k) {printf("%lld
    ",v[i].first);break;}
    46     return 0;
    47 }
    数集公理化构造

      然而,我发现其他人根本没有这样想……

      hzwer如是说:

      本题似乎要先知道许多结论,不要问我证明。。

      一个数约数个数=所有素因子的次数+1的乘积

      举个例子就是48 = 2 ^ 4 * 3 ^ 1,所以它有(4 + 1) * (1 + 1) = 10个约数

      然后可以通过计算得一个2000000000以内的数字不会有超过12个素因子

      并且小素因子多一定比大素因子多要优

      预处理出前12个素数直接爆搜即可

      霎时间感觉自己被打脸。所谓的结论是:不超过N的最大的反质数是1~N间约数最多且相对最小的值x。很明显,这样的数x是一个反质数。若1~N间存在着更大的反质数,则显然月数个数比x多,与x约数最多矛盾。

      于是只需找1~N间约数最多且相对最小的值x,暴搜居然效率也很高。

      但是,暴搜和我的方法时间差不多,而我却算出了所有的反质数。若要打表,显然更优。 

  • 相关阅读:
    奇数阶魔方问题
    《DSP using MATLAB》示例9.3
    《DSP using MATLAB》示例9.2
    《DSP using MATLAB》示例9.1
    找个目标很重要
    《DSP using MATLAB》示例Example 8.30
    《DSP using MATLAB》示例Example 8.29
    《DSP using MATLAB》示例Example 8.28
    《DSP using MATLAB》示例Example 8.27
    《DSP using MATLAB》示例Example 8.26
  • 原文地址:https://www.cnblogs.com/Doggu/p/bzoj1053.html
Copyright © 2011-2022 走看看