先搞清楚几点:
1.题目中没有说ai是互不相同的,所以可能有多个ai;
2.题目中的目标序列是说,在目标序列中,任意两个元素都有倍数关系,即约数关系,让我们求序列的最大长度,很明显的感觉是个dp问题(这个坑我们以后再填)
(1)状态定义:我们很容易想到的是对于原序列的每一个数,都去更新他倍关系的数量,比如2就可以去4的数量,我们认为2和4可以构成一段目标序列,那么dp[4]就是2
问题:上述思路其实是存在一定问题的,就比如2是6的约数,3是6的约数,但是2和3并不是约数关系,那么,6就需要选择最大的一个约数,而不是全部的约数,就有了下面的状态转移方程
(2)状态转移方程:dp[j] = max(dp[j],dp[i])其中j是一个较大的数,i是j的约数之一
3.有了上述思路,我们最容易想到的就是一个暴力做法,即对任何一个在原区间内的数都更新他的倍数,如果更新的数是原序列的数,就状态转移
暴力算法相对慢一点,因为一倍两倍三倍的枚举是很慢的,我们下边说一个数论优化
即对原序列中从minn -> maxx所有的数,都只乘素数倍,因为根据算术基本定理,任何数都是多个素数因子的乘积。这个是很快的,因为1e7内的素数是很少的,大约 6 * 1e5 个,而且有些很大的就超maxx了。
题目描述
In MI Intelligent Warehouse, there are nn_{}n products, where the ii_{}i-th product is of size aia_iai. We always need to box producsts into all kinds of containers, and it will be safer and more cost efficient if for any two sizes of products, one is the other's multiple, since there won't be any residual room in one container. So for each boxing we need to choose some products that for any two chosen products, either aia_iai is multiple of aja_jaj or aja_jaj is multiple of aia_iai. Print the maximum number of products that can be chosen in one boxing.
输入描述:
The first line contains one integer n (1≤n≤2×105)n~(1\le n \le 2\times 10^5)n (1≤n≤2×105).
The second line contains nn_{}n integers a1,a2,⋯ ,an (1≤ai≤107)a_1, a_2, \cdots, a_n~(1\le a_i \le 10^7)a1,a2,⋯,an (1≤ai≤107).
输出描述:
Only one line containing one integer, denoting the maximum number of products we can choose in one boxing.
示例1
输入
复制6 1 4 2 8 5 7
6 1 4 2 8 5 7
输出
复制4
4
说明
One possible choice is {1, 4, 2, 8}.
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
const int N = 1e7 + 15;
const int MAXN = 2 * 1e5 + 15;
int dp[N],num[N];
int a[MAXN];
bool book[N];
int main()
{
int n,maxx = 0;
cin >> n;
for(int i = 0; i < n; i ++)
{
scanf("%d",&a[i]);
num[a[i]] ++;
maxx = max(a[i],maxx);
}
sort(a,a + n);
int x;
for(int i = 0; i < n; i ++)
{
x = a[i];
if(book[x]) continue;
book[x] = true;
dp[x] += num[x];
for(int j = 2; j * x <= maxx; j ++)
{
if(num[j * x]) dp[j * x] = max(dp[j * x], dp[x]);
}
}
int res = 0;
for(int i = 0; i < n; i ++) res = max(dp[a[i]],res);
cout << res << endl;
return 0;
}
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 1e7 + 15;
const int MAXN = 2 * 1e5 + 15;
int dp[N],num[N],primes[N],cnt;
int a[MAXN];
bool book[N];
void get_primes(int m)
{
for(int i = 2; i <= m; i ++)
{
if(!book[i]) primes[cnt ++] = i;
for(int j = 0; j < cnt && primes[j] * i <= m; j ++)
{
book[primes[j] * i] = true;
if(i % primes[j] == 0) break;
}
}
}
int main()
{
int n,maxx = 0;
cin >> n;
for(int i = 0; i < n; i ++)
{
scanf("%d",&a[i]);
num[a[i]] ++;
maxx = max(maxx,a[i]);
}
get_primes(maxx);
int res = 0;
for(int i = 1; i <= maxx; i ++)
{
if(!dp[i] && !num[i]) continue;
dp[i] += num[i];
res = max(dp[i],res);
for(int j = 0; j < cnt && primes[j] * i <= maxx; j ++)
{
dp[primes[j] * i] = max(dp[primes[j] * i],dp[i]);
res = max(dp[primes[j] * i] , res);
}
}
cout << res << endl;
return 0;
}