原题链接
这个题显然是一个dp题。对杂草高度简单排个序,关键点在于状态的设计。
下意识地,我们会令
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j]表示考虑前i棵杂草,先拔掉其中j棵,最后所需的操作次数。
显然有
d
p
[
i
]
[
j
]
=
m
i
n
(
d
p
[
i
−
1
]
[
j
−
1
]
,
d
p
[
l
o
w
e
r
_
b
o
u
n
d
(
A
+
1
,
A
+
N
+
1
,
A
[
i
]
/
2
+
1
)
−
A
−
1
]
[
j
]
+
1
)
dp[i][j]=min(dp[i-1][j-1],dp[lower\_bound(A+1,A+N+1,A[i]/2+1)-A-1][j]+1)
dp[i][j]=min(dp[i−1][j−1],dp[lower_bound(A+1,A+N+1,A[i]/2+1)−A−1][j]+1)
然而这样做的话,状态数目太多了,就算是滚动数组优化了空间,时间也不够。
考虑将状态中的一维与所求值调换一下:
令
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j]表示考虑前i棵杂草,我们操作j次,最多可以拔掉其中多少棵。注意到j最多为
l
g
2
(
m
a
x
(
A
[
i
]
)
)
lg2(max(A[i]))
lg2(max(A[i]))级别,即
32
32
32左右。
显然有
t
m
p
=
l
o
w
e
r
_
b
o
u
n
d
(
A
+
1
,
A
+
N
+
1
,
A
[
i
]
/
2
+
1
)
−
A
−
1
tmp=lower\_bound(A+1,A+N+1,A[i]/2+1)-A-1
tmp=lower_bound(A+1,A+N+1,A[i]/2+1)−A−1
d
p
[
i
]
[
j
]
=
m
a
x
(
d
p
[
i
−
1
]
[
j
]
,
d
p
[
t
m
p
]
[
j
−
1
]
+
i
−
t
m
p
)
dp[i][j]=max(dp[i-1][j],dp[tmp][j-1]+i-tmp)
dp[i][j]=max(dp[i−1][j],dp[tmp][j−1]+i−tmp)
最后我们只需要找到最小的k使得
N
−
d
p
[
N
]
[
k
]
≤
K
N-dp[N][k] \le K
N−dp[N][k]≤K
然后答案便是
k
k
k与
N
−
d
p
[
N
]
[
k
]
N-dp[N][k]
N−dp[N][k]
#include<bits/stdc++.h>
using namespace std;
const int MAXN=2e5+5;
int N,K;
int A[MAXN];
int dp[MAXN][32];
int find(int i){
int h=A[i]/2+1;
int j=lower_bound(A+1,A+N+1,h)-A;
return j-1;
}
int main(){
//freopen("in.txt","r",stdin);
ios::sync_with_stdio(false);
cin>>N>>K;
for(int i=1;i<=N;i++)
cin>>A[i];
sort(A+1,A+N+1);
memset(dp,-0x3f,sizeof(dp));
for(int i=0;i<32;i++)
dp[0][i]=0;
for(int i=1;i<=N;i++)
for(int j=0;j<32;j++){
int tmp=find(i);
dp[i][j]=max(dp[i-1][j],(j>=1?dp[tmp][j-1]+i-tmp:0));
}
for(int i=0;i<32;i++)
if(N-dp[N][i]<=K){
cout<<i<<" "<<N-dp[N][i]<<endl;
break;
}
return 0;
}