朴素的算法是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.