ABC403D
观察到一个数 \(x\) 是否删除取决于 \(x+d\) 和 \(x-d\) 是否删除。考虑 dp,设 \(f_{i,0/1}\) 表示当前为数字 \(i\) 的最少删除次数,其中 \(0\) 表示删除 \(i\),\(1\) 表示不删除,则应当由 \(f_{i-d,0/1}\) 转移过来。具体地,有:
\[f_{i,0}=\min(f_{i-d,0},f_{i-d,1})+b_i
\]
\[f_{i,1}=f_{i-d,0}
\]
其中 \(b_i\) 表示 \(i\) 的出现次数。最后答案为 $ \sum_{i=M-d+1}^M \min(f_{i,0},f_{i,1})$,其中 \(M\) 为值域上限。时间复杂度 \(O(N+M)\),实现时注意边界情况及特判 \(d=0\) 的情况。
#include<iostream>
#include<cstdio>
#include<map>
#define N 2000010
using namespace std;
int n,d,a[N],b[N],f[N][2],ans;
int main(){
cin>>n>>d;
for(int i=1;i<=n;i++)
cin>>a[i],b[a[i]]++;
if(d==0){//d=0时,相同的数只保留一个
for(int i=0;i<=1000000;i++)
if(b[i])
ans+=b[i]-1;
cout<<ans;
return 0;
}
for(int i=0;i<=1000000;i++){
if(i<d){
f[i][0]=b[i];
continue;
}
f[i][0]=min(f[i-d][0],f[i-d][1])+b[i];
f[i][1]=f[i-d][0];
}
for(int i=1000000;i>1000000-d;i--)
ans+=min(f[i][0],f[i][1]);
cout<<ans;
return 0;
}

浙公网安备 33010602011771号