题目链接:
51Nod
Codeforces
思路:
一个直接的思路是可以考虑枚举每个数,再枚举每一个数的倍数,正向搜索,易发现其为
O
(
n
l
o
g
l
o
g
n
)
O(nloglogn)
O(nloglogn)的复杂度
而我的思路是逆序 D P DP DP。
设
d
p
[
i
]
dp[i]
dp[i]是当
i
i
i这个数为合法解中的最小值时,包含的数的个数。
比如对于三个数:
6
,
12
,
24
6,12,24
6,12,24
则:
d
p
[
6
]
=
3
dp[6] = 3
dp[6]=3
d
p
[
12
]
=
2
dp[12] = 2
dp[12]=2
d
p
[
24
]
=
1
dp[24] = 1
dp[24]=1(只有它自己)
故可以先将所有数进行排序,然后逆向
O
(
n
)
O(n)
O(n)枚举每一个数
i
i
i,然后
O
(
l
o
g
n
)
O(logn)
O(logn)枚举每一个数的倍数
j
j
j,则:
d
p
[
i
]
=
m
a
x
(
d
p
[
j
]
)
+
1
dp[i] = max(dp[j]) + 1
dp[i]=max(dp[j])+1
对于 1 1 1来说,因为其为每一个数的约数,故可以直接特判。
故总复杂度: O ( n l o g n ) O(nlogn) O(nlogn)
另外此题因为数据较大,在51Nod若用C++ 或者 C++11均需要使用读入挂,否则会超时,而我是使用的Visual C++提交,则不存在以上问题。
代码:
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
const int A = 1e6 + 10;
int dp[A],a[A];
int main(){
int Mx = 0;
int n;scanf("%d",&n);
for(int i=1 ;i<=n ;i++) scanf("%d",&a[i]),Mx = max(Mx,a[i]);
sort(a+1,a+n+1);
int ans = 0;
for(int i=n ;i>=1 ;i--){
if(a[i] == 1) dp[a[i]] = ans + 1;
else{
dp[a[i]] = 1;
for(int j=2 ;a[i]*j<=Mx ;j++){
dp[a[i]] = max(dp[a[i]],dp[a[i]*j]+1);
}
}
ans = max(ans,dp[a[i]]);
}
printf("%d\n",ans);
return 0;
}