1. 程式人生 > 實用技巧 >陶陶摘蘋果

陶陶摘蘋果

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]<<'\n';
	return 0;
}
  • 考試時想到的DP三維轉移方程,涉及最遠的區間右端點,沒想到右端點排序