有趣的有趣的家庭菜园(C.c/cpp/pas/in/out)
(Time Limit:1s Memory Limit:256MB)
【Description】
职业经营家庭菜园的JOI君每年在自家的田地中种植一种叫做IOI草的植物。IOI草的种子在冬天被播下,春天会发芽并生长至一个固定的高度。到了秋天,一些IOI草会结出美丽的果实,并被收获,其他的IOI草则会在冬天枯萎。
JOI君的田地沿东西方向被划分为N个区域,从西侧开始的第i个区域中种植着IOI草i。在第i个区域种植的IOI草,在春天的时候高度会生长至Hi,此后便不再生长。如果IOI草i会结出果实,那么将会获得Pi的收益,否则没有收益。
春天到了,查看田地样子的JOI君决定拔掉一些种植的IOI草,使利益最大化。拔掉IOI草i需要Ci的花销,拔掉的IOI草会立刻枯萎。IOI草只能在春天被拔掉,夏天和秋天不能拔掉IOI草。
IOI草是一种非常依靠阳光的植物,如果在夏天某个区域的IOI草的东侧和西侧都有比它高的IOI草存在,那么这株IOI草在秋天便不会结出果实。换句话说,为了让没有被拔掉的IOI草i在秋天结出果实,到了夏天的时候,以下两个条件至少满足一个:
1.对于任意1<=j<=i-1,Hj<=Hi或IOI草j已经被拔除
2.对于任意i+1<=j<=N,Hj<=Hi或IOI草j已经被拔除
用最终收获的果实的总价格减掉拔除IOI草的花销的总和,即为JOI君的收益。那么JOI君能从IOI草中获取的最大利益到底有多少呢?
【Input】
第一行一个正整数N,表示田地被分为了N个区域。
接下来N行,第i行(1<=i<=N)三个空白分割的正整数Hi,Pi,Ci,表示第i株IOI草在春天时高度会生长至Hi,秋天收获的果实的价格为Pi,拔除所需费用为Ci。
【Output】
输出一行一个整数,表示JOI君能获得的最大利益
【Sample Input】
7
22 60 30
46 40 30
36 100 50
11 140 120
38 120 20
24 90 60
53 50 20
【Sample Output】
320
【HINT】
拔除IOI草2和IOI草7,剩余的IOI草如下图所示:
IOI草1、3、5、6的果实价格分别为60、100、120、90,拔除IOI草2和IOI草7的花销分别为30、20,总收益为320,这是所有方案中的最大值。
【Data Constraint】
对于30%的数据,N<=20
对于45%的数据,N<=300
对于60%的数据,N<=5000
对于100%的数据:
3<=N<=10^5
1<=Hi<=10^9 (1<=i<=N)
1<=Pi<=10^9 (1<=i<=N)
1<=Ci<=10^9 (1<=i<=N)
爆搜 30分
双向跑DP+线段树、离散化优化 AC
设状态f[i]表示i 这个IOI 草前面没有比它更高的草时,1-i 这些草的纯收益 ;转移为右面按照同样的方法处理,那么答案就是以某个草及其左面草的收益,和它严格右侧草的收益了;对高度做一个离散化,建一个线段树 ,查询比当前小或等于的最大值。
附代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<string>
#include<iomanip>
#include<ctime>
#include<climits>
#include<cctype>
#include<algorithm>
#define clr(a,x) memset(x,a,sizeof(x))
#define ll long long
#ifdef WIN32
#define AUTO "%I64d"
#else
#define AUTO "%lld"
#endif
using namespace std;
const int maxn = 100000;
int n,m;
ll ans,t;
int p[maxn+10];
ll f1[maxn+10],f2[maxn+10],num[maxn*4],ad[maxn*4];
struct node
{
ll h,p,c;
}a[maxn+10];
bool cmp(int x, int y)
{
return a[x].h < a[y].h;
}
template <class T> inline void read(T &xx)
{
xx = 0;
T flag = 1;
char ch = (char)getchar();
while(ch<'0' || ch>'9')
{
if(ch == '-') flag = -1;
ch = (char)getchar();
}
while(ch>='0' && ch<='9')
{
xx = (xx<<1) + (xx<<3) + ch - '0';
ch = (char)getchar();
}
xx *= flag;
}
void init()
{
read(n);
for(int i = 1; i <= n; i++)
{
read(a[i].h);
read(a[i].p);
read(a[i].c);
p[i]=i;
}
sort(p+1 ,p+n+1, cmp);
for(int i = 1; i <= n; i++)
if(a[p[i]].h != t)
{
t = a[p[i]].h;
a[p[i]].h = ++m;
}
else a[p[i]].h = m;
clr(200,num);
return;
}
void pushdown(int i)
{
num[i*2] += ad[i];
ad[i*2] += ad[i];
num[i*2+1] += ad[i];
ad[i*2+1] += ad[i];
ad[i] = 0;
return;
}
ll query(int i, int l, int r, int x, int y)
{
int mid = (l + r) >> 1;
if(l == x && r == y) return num[i];
if(ad[i] != 0) pushdown(i);
if(y <= mid)
return query(i*2,l,mid,x,y);
if(x > mid)
return query(i*2+1,mid+1,r,x,y);
if(x <= mid && y > mid)
return max(query(i*2,l,mid,x,mid), query(i*2+1,mid+1,r,mid+1,y));
}
void updata(int i, int l, int r, int x, int y, ll z)
{
int mid = (l + r) >> 1;
if(l == x && r == y)
{
num[i] += z;
ad[i] += z;
return;
}
if(ad[i] != 0) pushdown(i);
if(y <= mid)
updata(i*2,l,mid,x,y,z);
if(x > mid)
updata(i*2+1,mid+1,r,x,y,z);
if(x <= mid && y > mid)
{
updata(i*2,l,mid,x,mid,z);
updata(i*2+1,mid+1,r,mid+1,y,z);
}
num[i] = max(num[i*2], num[i*2+1]);
return;
}
void edit(int i, int l, int r, int x, ll y)
{
int mid = (l + r) >> 1;
if(l == r)
{
num[i] = y;
return;
}
if(ad[i] != 0) pushdown(i);
if(x <= mid) edit(i*2,l,mid,x,y);
else edit(i*2+1,mid+1,r,x,y);
num[i] = max(num[i*2], num[i*2+1]);
return;
}
int main()
{
freopen("c.in","r",stdin);
freopen("c.out","w",stdout);
init();
edit(1,0,m,0,0);
for(int i = 1; i <= n; i++)
{
f1[i] = a[i].p + query(1,0,m,0,a[i].h);
updata(1,0,m,0,a[i].h,-a[i].c);
edit(1,0,m,a[i].h,f1[i]);
}
clr(200,num); clr(0,ad);
edit(1,0,m,0,0);
for(int i = n; i >= 1; i--)
{
f2[i] = a[i].p + query(1,0,m,0,a[i].h);
updata(1,0,m,0,a[i].h,-a[i].c);
edit(1,0,m,a[i].h,f2[i]);
}
for(int i = 1; i <= n; i++)
ans = max(ans, f1[i]+f2[i]-a[i].p);
printf(AUTO, ans);
return 0;
}