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

来源:互联网 发布:阿里云主机试用 编辑:程序博客网 时间:2024/05/22 05:14

题目描述

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

输入

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

输出

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

样例输入

1 100

样例输出

8 2 4 6 12 24 36 48 60

数据范围限制

对于30%的数据,1<=l<=r<=200000。
对于50%的数据,1<=l<=r<=500000。
对于70%的数据,保证最大的约数国王的约数的个数不大于1000。

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


c(x)表示有x个约数的正整数

c(x)是约数国王当且仅当c(x)<min(c(x+1),c(x+2)...c(x+k))(k趋向于无穷大)

证明:(反证法)
假设c(x)>min(c(x+1),c(x+2)...c(x+k)),并且c(x)是约数国王,

min(c(x+1),c(x+2)...c(x+k))c(x+i)c(x)>c(x+i)但是x<x+i,所以c(x)不可能是约数国王。

证毕。

如果我们求出了所有的c(x),就可以用上述方法求出c(x)是不是约数国王。

 

那么问题就转化成怎么求出c(x)

我们设f[x][y]表示当前到了含有前x个质数,有y个约数的最小正整数。

f[x+1][y*(k+1)]=min(f[x+1][y*(k+1)],F[x][y]*p[x]k)

我们求出f数组之后,c[x]=min(f[i][x])

那么c数组就求出来了,问题就解决了。


等这道题的人一定很多吧,这么坑的题(呵呵呵呵呵)

const maxn=161281; maxint=9223372036854775807; zs:array[1..31]of longint=(2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,57,61,67,71,73,79,83,89,97,101,103,107,109,113,127);var f,q:array[1..13,1..170000]of qword; l,r,sum,min:int64; c,b:array[1..170000]of qword;procedure dp;var i,j,k,o:longint; p:qword;begin for i:=1 to 13 do  for j:=1 to 170000 do   f[i,j]:=maxint;  f[1,1]:=1;  f[1,2]:=2;  for i:=3 to 63 do   f[1,i]:=f[1,i-1]*2;  fillchar(q,sizeof(q),1); for i:=1 to 12 do  for j:=1 to 81000 do  begin   p:=1;    if q[i,j]>maxn div j then o:=maxn div j    else o:=q[i,j];    for k:=1 to o do    begin     if maxint div zs[i+1]<p then break;     p:=p*zs[i+1];     if maxint div p<f[i,j] then break;     if f[i,j]*p<f[i+1,j*(k+1)] then begin     f[i+1,j*(k+1)]:=f[i,j]*p;     q[i+1,j*(k+1)]:=k;     end;    end;   end;end;procedure main;var i,j:longint;begin readln(l,r); dp; fillchar(c,sizeof(c),$7); b[maxn+1]:=maxint; for i:=maxn downto 1 do  begin   min:=maxint;   for j:=1 to 13 do   if f[j,i]<min then min:=f[j,i];   c[i]:=min;   if c[i]<b[i+1] then b[i]:=c[i] else b[i]:=b[i+1];  end;  for i:=2 to maxn do   if (c[i]<b[i+1])and(c[i]>=l)and(c[i]<=r) then inc(sum);end;procedure print;var i,j:longint;begin for i:=2 to maxn do  if (c[i]>=l)and(c[i]<=r)and(c[i]<b[i+1]) then write(c[i],' ');end;begin  assign(input,'king.in');reset(input);  assign(output,'king.out');rewrite(output); main; write(sum,' '); print; close(input); close(output);end.

2 0