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;
}
posted @ 2025-09-12 08:07  FormulaOne  阅读(5)  评论(0)    收藏  举报