天天看点

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

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

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

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

题目描述

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