题意
定义一个数组是好的,当对于任意的 \(i\) 和 \(j\) ,有 \(a_i|a_j\) 或者 \(a_j|a_i\) 。给出数组 \(a\) ,求出最少要删除多少个元素可以使得 \(a\) 数组是好的。
\(1≤t≤10,1≤n≤2⋅10^5,1≤a_i≤2⋅10^5\)
题目链接:https://codeforces.com/contest/1475/problem/G
分析
定义 \(dp[i]\) 表示以 \(i\) 为最大的元素且每个元素均属于原数组的好数组的最大大小,\(num[i]\) 表示原数组中 \(i\) 出现的次数,显然有:
\[dp[i]=num[i]+\max_{x=1,x|i,x\in a}^{i-1}dp[x] \]求出最大的 \(dp[i]\) 即可,因子可以用埃式筛处理。关键在于思考问题的角度,想到了就好写。
代码
#include <bits/stdc++.h>
#define pb push_back
using namespace std;
const int N=2e5+5;
int dp[N],num[N],a[N];
vector<int>pd[N];
void read(int &x)
{
x=0;
int f=1;
char ch=getchar();
while(!isdigit(ch))
{
if(ch=='-')
f=-1;
ch=getchar();
}
while(isdigit(ch))
{
x=(x<<3)+(x<<1)+ch-'0';
ch=getchar();
}
x*=f;
}
int main()
{
int t,n;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
int maxn=0,cnt=0,x;
for(int i=0;i<=2e5;i++) num[i]=0,dp[i]=0,pd[i].clear();
for(int i=1;i<=n;i++)
{
read(x);
if(num[x]==0)
a[++cnt]=x;
num[x]++;
maxn=max(maxn,x);
}
sort(a+1,a+1+cnt);
for(int i=1;i<=cnt;i++)
{
for(int j=a[i]+a[i];j<=maxn;j+=a[i])
pd[j].pb(a[i]);
}
int ans=0;
for(int i=1;i<=cnt;i++)
{
int tmp=0;
for(auto j:pd[a[i]])
tmp=max(tmp,dp[j]);
dp[a[i]]=num[a[i]]+tmp;
ans=max(dp[a[i]],ans);
}
printf("%d\n",n-ans);
}
return 0;
}