关闭

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

441人阅读 评论(0) 收藏 举报
分类:

【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

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:14134次
    • 积分:948
    • 等级:
    • 排名:千里之外
    • 原创:82篇
    • 转载:5篇
    • 译文:1篇
    • 评论:4条