题目链接:点击这里
题目大意:
给定一个长度为
n
n
n 的序列
a
i
a_i
ai ,求从
a
i
a_i
ai 中至少删除几个元素可以得到一个序列
b
i
b_i
bi ,其满足对于任意的
i
,
j
i,j
i,j 有
b
i
∣
b
j
b_i|b_j
bi∣bj 或
b
j
∣
b
i
b_j|b_i
bj∣bi
题目分析:
考虑设计状态
d
p
[
i
]
dp[i]
dp[i] 表示以
i
i
i 结尾的最大的满足题目要求的集合的大小,那么答案就变成了
n
−
m
a
x
(
d
p
i
)
n-max(dp_i)
n−max(dpi)
考虑如何转移该:因为每个集合中任意两个数都是有整除关系,而整除关系又具有传递性(
i
∣
j
,
j
∣
k
−
>
i
∣
k
i|j,j|k->i|k
i∣j,j∣k−>i∣k ),所以有转移方程:
d
p
[
i
]
=
c
n
t
[
i
]
+
m
a
x
(
d
p
[
j
]
)
dp[i] = cnt[i]+max(dp[j])
dp[i]=cnt[i]+max(dp[j]) 其中
i
∣
j
i|j
i∣j
时间复杂度为
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn)
具体细节见代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<set>
#include<map>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
int read()
{
int res = 0,flag = 1;
char ch = getchar();
while(ch<'0' || ch>'9')
{
if(ch == '-') flag = -1;
ch = getchar();
}
while(ch>='0' && ch<='9')
{
res = (res<<3)+(res<<1)+(ch^48);//res*10+ch-'0';
ch = getchar();
}
return res*flag;
}
const int maxn = 2e5+5;
const int mod = 1e9+7;
const double pi = acos(-1);
const double eps = 1e-8;
int n,maxx,cnt[maxn],a[maxn],dp[maxn];
int main()
{
int t = read();
while(t--)
{
n = read();
for(int i = 1;i <= n;i++) cnt[a[i] = read()]++,maxx = max(maxx,a[i]);
for(int i = maxx;i;i--)
for(int j = i;j <= maxx;j += i) dp[i] = max(dp[i],cnt[i]+dp[j]);
printf("%d\n",n-*max_element(dp+1,dp+maxx+1));
for(int i = 1;i <= maxx;i++) dp[i] = cnt[i] = 0;maxx = 0;
}
return 0;
}