ABC 203F WEED

原题链接
这个题显然是一个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[i1][j1],dp[lower_bound(A+1,A+N+1,A[i]/2+1)A1][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)A1
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[i1][j],dp[tmp][j1]+itmp)
最后我们只需要找到最小的k使得 N − d p [ N ] [ k ] ≤ K N-dp[N][k] \le K Ndp[N][k]K
然后答案便是 k k k N − d p [ N ] [ k ] N-dp[N][k] Ndp[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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值