朴素的算法是O(n2logn)
观察这个算法,似乎很难在进行优化
我们就要换一种思路
考虑到一个数的约数总不是很多,穷举约数也是可以在O(sqrt(x))的时间内完成的
并且注意到,能否继续往下选数,只在于最后一个被选中的数
设f[x]当前最后一个选中的数和上一个可以被选中的数的gcd为x时最多选的数的个数
顺着扫描可得到f[x]=max(f[y])+1 (if y|ai且ai/y>=L,x>=L x|ai )
对于这个方程的转移,我们可以先用k记录max(f[y]) (if y|ai且ai/y>=L)
然后转移f[x]=k+1 (x>=L x|ai )
然后就可以解决了

 1 var f,a:array[0..1000010] of longint;
 2     i,j,k,ans,n,m,l:longint;
 3 
 4 function max(a,b:longint):longint;
 5   begin
 6     if a>b then exit(a) else exit(b);
 7   end;
 8 
 9 begin
10   readln(n,l);
11   for i:=1 to n do
12   begin
13     read(a[i]);
14     if a[i]>m then m:=a[i];
15   end;
16   for i:=1 to n do
17   begin
18     k:=0;
19     for j:=1 to trunc(sqrt(a[i])) do
20       if a[i] mod j=0 then
21       begin
22         k:=max(k,f[j]);
23         k:=max(k,f[a[i] div j]);
24       end;
25     inc(k);
26     for j:=1 to trunc(sqrt(a[i])) do
27       if a[i] mod j=0 then
28       begin
29         if j>=l then f[j]:=k;
30         if a[i] div j>=l then f[a[i] div j]:=k;
31       end;
32   end;
33   ans:=0;
34   for i:=l to m do
35     ans:=max(ans,f[i]);
36   writeln(ans);
37 end.
View Code

 

posted on 2014-10-26 17:31  acphile  阅读(99)  评论(0编辑  收藏  举报