反质数(noi题库)

来源:互联网 发布:win10无法磁盘优化 编辑:程序博客网 时间:2024/04/29 20:16


题目:http://noi.openjudge.cn/ch0407/7591/

简单爆搜肯定会超时~剪枝也没用~

∵2*3*...*31>20000000 ∴不同质因子个数最多12个

且同样多的因数,质因子小的总比用质因子大的合算

枚举每个质因子的次方(不超过25,∵2^25>20000000),定义数组ans[i],表示质因子个数为i的最小数,这是一个用深搜进行的不断更新ans的过程,而且并不需要线性更新。

直接求20000000以内所有的ans,在读入n,m,进行输出(并非打表)

还有一个地方至关重要,在程序中用红色标出:


程序:

var q:array[0..1000,1..2]of longint;
  a:array[1..12]of integer=(2,3,5,7,11,13,17,19,21,23,29,31);
  ans:array[1..100000]of longint;
  n,m,i,j,p,k,pre,t1:longint;
  flag:boolean;

procedure dfs(now,tot,id:int64);
var
  i,s,j:longint;
begin
  if id>12then begin
    if ans[tot]>nowthen ans[tot]:=now;
    exit;
  end;
  for i:=0to 25 do begin
    s:=1;
    for j:=1to i do begin
      s:=s*a[id];
      if s*now>20000000then break;
    end;
    if s*now>20000000then break;
    dfs(now*s,tot*(1+i),id+1);
  end;
end;

begin
  //assign(input,'a.in');reset(input);
  //assign(output,'a.out');rewrite(output);
  readln(n,m);
  for i:=1to 1000 do ans[i]:=maxlongint;
  dfs(1,1,1);
  for i:=1to 1000 do
    if ans[i]=maxlongintthen ans[i]:=0;
  flag:=true;
  k:=0;
  {for i:=1 to 1000 do
if (ans[i]<>0) and (ans[i]<=m) and (ans[i]>=n) then begin
write(ans[i],',');
end;
writeln;}
  for i:=1to 1000 do
    if (ans[i]<>0)then begin
      inc(k);
      q[k,1]:=ans[i];
      q[k,2]:=k;
    end;
  for i:=1to k-1 do
    for j:=i+1to k do
      if q[i,1]>q[j,1]then begin
        p:=q[i,1];q[i,1]:=q[j,1];q[j,1]:=p;
        p:=q[i,2];q[i,2]:=q[j,2];q[j,2]:=p;
      end;
  p:=-1;pre:=0;
  for i:=1to k do
    if (q[i,2]>q[pre,2])then  begin    //直接举个例子来说,ans[5]=16;ans[6]:=12;应取ans[6]而非ans[5],对于ans[i]>ans[j]且i<j的情况应取ans[j]
      if (q[i,1]>=n)and (q[i,1]<=m)then begin
        if flag thenbegin
          write(q[i,1]);
          flag:=false;
        end
        else write(',',q[i,1]);
      end;
      pre:=i;
    end;
  if not flag then writeln
  else writeln('NO');
  readln;
  //close(input);close(output);
end.

0 0
原创粉丝点击