【2016.5.21普及组模拟】约数国王(A king)

来源:互联网 发布:java 数据字典表设计 编辑:程序博客网 时间:2024/05/20 13:08

【2016.5.21普及组模拟】约数国王(A king)


(File IO): input:king.in output:king.out

时间限制: 1000 ms 空间限制: 262144 KB 具体限制

Description
数学的王国里,有一些约数国王……约数国王的定义是这样的:一个大于1的整数n,如果它约数的个数比1~n-1的每个整数的约数的个数都要多,那么我们就称它为约数国王。聪明的小明在奥数书上认识了它们,于是产生了一个问题:他想知道L到R之间一共有多少个约数国王?它们分别又是谁?

Input
输入文件只有一行,包含一个l,一个r,表示小明想知道的范围。

Output
只有一行,第一个数h,表示l~r内一共有多少个约数国王,接下来h个从小到大的数(为了防止国王们打架,你需要按顺序输出。),表示约数国王分别是谁。

Sample Input
1 100

Sample Output
8 2 4 6 12 24 36 48 60

Data Constraint

  • 对于30%的数据,1<=l<=r<=200000。
  • 对于50%的数据,1<=l<=r<=500000。
  • 对于70%的数据,保证最大的约数国王的约数的个数不大于1000。
  • 对于100%的数据,1<=l<=r, 并且保证l,r在64位整型以内,最大的约数国王的约数的个数不大于200000。

解题思路


首先,我们设一个c[i],表示因数个数(包括本数)为i,的最小正整数,那么对于一个数c[i],如果c[i]<任何一个c[i+k] (k为正整数),那么c[i]就是一个约数国王。

对于求出c[i],我们可以设P[i]为从小到大的质数中的第i个。这里用线性筛法可以求出来。

我们可以在设一个F[i,j]表示,有i个不同质因数构成,有j个因数的最小正整数。
那么,c[i]=Max{F[k,i]}。

求一个数的因子个数的公式:
N=P1A1+P2A2+P3A3+...+PmAm也就是N=mi=1PiAi (这里所有的P都是质数),那么,N的因数个数为(A1+1)(A2+1)(A3+1)…(Am+1)。
证明:
若M是N的因数,M=P1K1+P2K2+P3K3+...+PmKm也就是M=mi=1PiKi (Ki<=Ai),那么,只要Ki选0~Ai,M|N,根据乘法原理,N的因数个数=mi=1(Ai+1) 也就是

(A1+1)(A2+1)(A3+1)...(Am+1)

那么F的转移方程如此:

F[i+1,j(k+1)]=min(F[i,j]P[i+1]k)

为什么要乘以P[i+1]k呢,你想想,选i+1个素数,当然是选前i个最优。

那我们来讨论一下j的取值范围,可想到2i<=j<=mx,mx为数组开的下限,为什么是2的i次方呢,我们在选第i+1个素数时,前面已经选了i个了,每一个素数最少选1个,就会有2i个因子,故如此。

那么代码就很容(kun)易(nan)想象出来了

Codes:

const    mxn=170000;    num=200000;    o=50;    mx=trunc(ln(mxn)/ln(2));    limit=9223372036854775807;var    f:array[1..mx,1..mxn]of qword;    c:array[1..mxn]of qword;    pr:Array[1..num] of longint;    bz:array[2..num]of boolean;    ans:array[1..mxn]of qword;    tot,i,j,k,top:longint;    l,r,x,t,max:qword;    p:boolean;procedure GetPrimes;begin    for i:=2 to num do    begin        if not bz[i] then        begin            inc(top);            pr[top]:=i;        end;        for j:=1 to top do        begin            if pr[j]*i>num then break;            bz[pr[j]*i]:=true;            if i mod pr[j]=0 then break;        end;    end;end;function min(p,q:qword):qword;begin    if p<q then exit(p) else exit(q);end;begin    assign(input,'king.in'); reset(input);    assign(output,'king.out'); rewrite(output);    read(l,r);    GetPrimes;    for j:=1 to mxn do    begin        for i:=1 to mx do f[i,j]:=limit;        c[j]:=limit;    end;    f[1,1]:=1;    c[1]:=1;    for i:=1 to 62 do    begin        f[1,i+1]:=f[1,i]<<1;        c[i+1]:=f[1,i+1];    end;    for i:=1 to mx-1 do        for j:=1<<i to mxn do        begin            if f[i,j]<limit then            begin                t:=1;                for k:=1 to mxn div j-1 do                begin                    if limit/t<pr[i+1] then break;                    t:=t*pr[i+1];                    if limit/t<f[i,j] then break;                    f[i+1,j*(k+1)]:=min(f[i+1,j*(k+1)],f[i,j]*t);                    c[j*(k+1)]:=min(c[j*(k+1)],f[i+1,j*(k+1)]);                end;            end;        end;    max:=limit;    for i:=mxn downto 2 do    begin        if c[i]<max then        begin            max:=c[i];            if (l<=c[i]) and (c[i]<=r) then            begin                inc(tot);                ans[tot]:=c[i];            end;        end;    end;    write(tot);    for i:=tot downto 1 do write(' ',ans[i]);    close(output); close(input);end.
1 0
原创粉丝点击