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

题目描述

 数学的王国里,有一些约数国王……约数国王的定义是这样的:一个大于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)趋向于无穷大)

证明:(反证法)
假设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,所以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]

then break; p:=p*zs[i+1]; if maxint div pthen break; if f[i,j]*p1,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]then min:=f[j,i]; c[i]:=min; if c[i]1] then b[i]:=c[i] else b[i]:=b[i+1]; end; for i:=2 to maxn do if (c[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]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.


你可能感兴趣的:(dp)