D - Forbidden Difference
题目链接:https://atcoder.jp/contests/abc403/tasks/abc403_d
题意:
给定一些数,要求删去一些数使得任意一个数x都不能存在x+d,x-d
求删除操作最少次数为多少?
思路:
通过桶来记录每个数的出现次数,那么对于起点为[0,d-1]的模序列(即每次+d,易知包含了所有情况)
我们需要做的是,对于每一个不同的数开头的模序列,维护每个数大小相差超过d
有一种思想是只删除奇数或偶数位置上的数
然而当一个模序列是这样子的:
d=1
num: 1 2 3 4 5 6
次数: 100 1 1 1 1 100
发现只删除奇数:100 + 1 + 1
只删除偶数: 1 +1 100
而最优的情况为删除中间4个数
(即可以连续删除一些数,而非每次跳一个删除)
所以我们需要用dp做
对于每一个序列,记dp[i][0]:遍历到i,且不删除i
dp[i][1]:遍历到i,且选i
dp[i][0] <- dp[i-1][1]
dp[i][1] <- min:dp[i-1][1],dp[i-1][0] + ..
需要注意的是:
1.d需要特判0
2.每个模序列如果中途某个数计数为0,那么这一段就要单独做dp
3.最后循环结束时也需要判断是否做不做dp
int cnt[maxn];
void solve(){
int n,d;cin>>n>>d;
rep(i,1,n){
int x;cin>>x;
cnt[x]++;
}
int ans=0;
if(d==0){
for(int i=0;i<=1e6;i++){
if(cnt[i])ans+=cnt[i]-1;
}
cout<<ans<<endl;return;
}
for(int i=0;i<=d-1;i++){
vector<int>x;
for(int j=i;j<=1e6;j+=d){
if(cnt[j]){
x.pb(cnt[j]);
}else{
if(x.size()<=1){
x.clear();continue;
}
vector<vector<int>>dp(x.size(),vector<int>(2,llmax));
for(int p=0;p<x.size();p++){
if(p==0){
dp[p][0]=0;
dp[p][1]=x[p];
}else{
dp[p][0]=dp[p-1][1];
dp[p][1]=min(dp[p-1][0],dp[p-1][1])+x[p];
}
}
ans+=min(dp[x.size()-1][1],dp[x.size()-1][0]);
x.clear();
}
}
if(x.size()>1){
vector<vector<int>>dp(x.size(),vector<int>(2,llmax));
for(int p=0;p<x.size();p++){
if(p==0){
dp[p][0]=0;
dp[p][1]=x[p];
}else{
dp[p][0]=dp[p-1][1];
dp[p][1]=min(dp[p-1][0],dp[p-1][1])+x[p];
}
}
ans+=min(dp[x.size()-1][1],dp[x.size()-1][0]);
x.clear();
}
}
cout<<ans<<endl;
}

浙公网安备 33010602011771号