陶陶摘苹果

Description

  陶陶家的院子里有一棵苹果树,每到秋天树上就会结出 n 个苹果。苹果成熟的时候,陶陶就会跑去摘苹果。
  陶陶的手不能弯 (他仅能把手伸直),当且仅当陶陶达到的高度与苹果的高度相等的时候,陶陶才能摘到苹果。
  好在陶陶有m个板凳,每个板凳的高度可以在区间[li, ri]之间上下移动 (即可以随时变为该区间中任何一个值)。当她不能直接用手摘到苹果的时候,就会踩到板凳上再试试。
  但是搬板凳对陶陶来说是一件费力的事情,所以他只能选择 k 个板凳来使用。
  现在已知n个苹果到地面的高度,m个板凳的高度区间,陶陶能选择的板凳数k,以及陶陶把手伸直能达到的高度h,请帮陶陶算一下她最多能够摘到的苹果的数目。假设她碰到苹果,苹果就会掉下来。

Input

  第一行四个正整数n,m,h,k,表示苹果的数量、板凳的数量、陶陶把手伸直能达到的高度和陶陶最多选择的板凳数量。
  第一行包含n个正整数,第i个正整数ai表示第i个苹果到地面的高度,两个相邻的整数之间用一个空格隔开。
  接下来m行,每行两个非负整数li,ri,表示第i个板凳的高度区间。

Output

  一个数,表示最多摘到的苹果数。

Sample Input

10 5 110 3
100 200 150 140 129 134 167 198 200 111
0 30
20 40
90 100
100 110
50 60

Sample Output

7

Hint

【数据范围与约定】
  对于 30% 的数据,m ≤ 10,ai, h ≤ 1000,li < ri ≤ 1000
  对于 100% 的数据,k ≤ m ≤ 200,n ≤ 1000000,ai, h ≤ 1000000,li < ri ≤ 1000000


思路

  • DP,f[i][j]表示选了i个板凳,这次选的是第j个
  • 优化,按照板凳的右端点进行排序
  • 注意,不踩板凳能摘到苹果也算摘到

代码

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn=1000000;
int n,m,h,k,num[maxn+5],sum[maxn+5],f[205][205];
struct fdfdfd{int left,right;}e[405];
bool cmp(fdfdfd a,fdfdfd b){return a.right<b.right;}
int main()
{
	scanf("%d%d%d%d",&n,&m,&h,&k);
	for(int i=1,temp;i<=n;++i) scanf("%d",&temp),++num[temp];
	for(int i=h+1;i<=maxn;++i) sum[i]=sum[i-1]+num[i];
	for(int i=1;i<=m;++i) scanf("%d%d",&e[i].left,&e[i].right),e[i].left+=h,e[i].right+=h;
	sort(e+1,e+m+1,cmp);
	for(int i=1;i<=k;++i)
		for(int j=1;j<=m;++j)
			for(int w=0;w<j;++w)
				f[i][j]=max(f[i][j],f[i-1][w]+sum[e[j].right]-sum[max(e[j].left-1,e[w].right)]);
	int ans=0;
	for(int i=1;i<=m;++i) ans=max(ans,f[k][i]);
	cout<<ans+num[h]<<'
';
	return 0;
}
  • 考试时想到的DP三维转移方程,涉及最远的区间右端点,没想到右端点排序
原文地址:https://www.cnblogs.com/wuwendongxi/p/13915692.html