Codeforces_484D:Kindergarten(贪心/DP)

原创 2017年01月03日 20:59:43

题目大意是说给定n个数字,要求你把它分成若干段连续的数列,每段有个贡献值,为这段数列中最大值与最小值之差,然后整个数列的贡献值为每段的贡献值之和,现在让你求该数列的最大贡献值.

由简单分析,便可得出每个分得的段落,一定满足:这段数字的最大值与最小值一定分别位于该段数字的边缘两侧,于是基于极值点做次贪心或dp就行...然后在调试了半天终于调对,再与好友的程序对比之后,才发现我的程序是辣么的长(害怕

下面附上我的丑陋的程序:

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
using namespace std;
#define ll long long
const int N=1000008;
ll n,a[N];
ll maxx(ll x,ll y){if(x>y)y=x;return y;}
ll minx(ll x,ll y){if(x<y)y=x;return y;}
ll maxx(ll x,ll y,ll z){if(x>z)z=x;if(y>z)z=y;return z;}
ll minx(ll x,ll y,ll z){if(x<z)z=x;if(y<z)z=y;return z;}
int main(void)
{
	ll i,p1,p2,p3,p4,p,pre,mi,ma;
	scanf("%I64d",&n);
	for(i=1;i<=n;i++)scanf("%I64d",a+i);a[0]=a[1];a[n+1]=a[n];
	p1=p2=p=0;pre=1;mi=ma=a[1];
	for(i=1;i<=n;i++)
	if(a[i]<a[i+1])
	{
		if(p>=0){p=1;mi=minx(mi,a[i]);ma=maxx(ma,a[i]);}
		else
		{
			p3=maxx(p1+(maxx(a[pre],ma)-minx(a[pre],mi))*(pre+1!=i),p2+(ma-mi)*(pre+1!=i));
			p4=maxx(p1+maxx(a[pre],ma,a[i])-minx(a[pre],mi,a[i]),p2+maxx(ma,a[i])-minx(mi,a[i]));
			p1=p3;p2=p4;pre=i;p=1;mi=ma=a[i+1];
		}
	}
	else if(a[i]>a[i+1])
	{
		if(p<=0){p=-1;mi=minx(mi,a[i]);ma=maxx(ma,a[i]);}
		else
		{
			p3=maxx(p1+(maxx(a[pre],ma)-minx(a[pre],mi))*(pre+1!=i),p2+(ma-mi)*(pre+1!=i));
			p4=maxx(p1+maxx(a[pre],ma,a[i])-minx(a[pre],mi,a[i]),p2+maxx(ma,a[i])-minx(mi,a[i]));
			p1=p3;p2=p4;pre=i;p=-1;mi=ma=a[i+1];
		}
	}
	else{mi=minx(mi,a[i]);ma=maxx(ma,a[i]);}
	p2=maxx(p1+maxx(a[pre],ma,a[n])-minx(a[pre],mi,a[n]),p2+maxx(ma,a[n])-minx(mi,a[n]));
	cout<<p2;
	return 0;
}

然后再附上学长的短到吓人的程序:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long ll;
ll num[1000010],ans;
int main()
{
    int T,t,n,m,i,j,k;
    ll ans=0,a=-1e9,b=-1e9,val;
    scanf("%d",&n);
    for(i=1;i<=n;i++)
    {
        scanf("%I64d",&val);
        a=max(a,ans+val);
        b=max(b,ans-val);
        ans=max(ans,a-val);
        ans=max(ans,b+val);
    }
    printf("%I64d\n",ans);
}

在询问学长&又思考了蛮久之后,终于看懂了学长的程序orz

由之前推出的性质,可以得到每段数列一定是形如[本段最大值...本段最小值]或者[本段最小值...本段最大值]

这样第一种情况的段贡献值便是val左-val右,而第二种情况相应是-val左+val右

这样对于每个读入的val,a存的是最大的"ans+val"即是算出第一种情况的左半边最优值,由于对于每个作为段落最右侧的val来说并不需要知道它左边是怎么决策的,而只需要知道左侧局部最优值,所以只需用a-val即补全右半部分式子后再尝试去更新最后答案,或者换种说法,即a已经算出了"前面分得的若干段贡献值"与"多出来的那半段数列的左端数字"之和,并对于每个val假设当前val为那半段数列的右端值并去更新答案;b也同理.总的来说,相当于ab存储了两种情况下当前各自的最优策略,然后在O(n)枚举时来尝试补全并更新最后的答案.

版权声明:本文为博主原创文章,未经博主允许不得转载。

Codeforces 484D Kindergarten(dp)

题目链接:Codeforces 484D Kindergarten 题目大意:给定一个序列,可以分为若干段,每份的值即为该段中的最大值减掉最小值。问说所有段的总和最大为多少。 解题思路:d...

【codeforces 484D】【DP】Kindergarten

传送门:http://codeforces.com/contest/484/problem/D 题意: 给定一个包含n个元素的数组,我们可以把位置连续的数分为一组,每组至少包含一个元素...

HDU 5558 Alice's Classified Message (后缀自动机水题) 2015年合肥区域赛G题

好久没写题解了唔..... 今天水了一题...写一下吧... 题目大意: 就是现在给出长度不超过10W的只包含小写字母的字符串,从下标0到 length - 1 现在从下标0开始进行操...

HDU4009 Transfer water 【最小树形图】

Transfer water Time Limit: 5000/3000 MS (Java/Others)    Memory Limit: 65768/65768 K (Java/Others...

[Codeforces 484D Kindergarten] DP

[Codeforces 484D Kindergarten] DP知识点:dynamic programming greedy1. 题目链接[Codeforces 484D Kindergarten]...

CodeForces 484D Kindergarten

题意: 将含有n(10^6)个元素的序列a划分成几段  每段为连续的一些元素  每段的价值为段中最大值减去最小值  总价值为所有段的价值和  求  最大的总价值 思路: 不难想到一个dp的转移方...

Codeforces 484A - Bits (贪心)

题意 输出[l, r]中二进制数字最多的数字。 思路 贪心,从r的最高位1开始和l比较,直到pos[r] = 1, pos[l] = 0,这时候就可以把r的当前位置置零,之前...

Codeforces 318 div2.D Bear and Blocks(dp,贪心)

题目: D. Bear and Blocks time limit per test 1 second memory limit per test ...

Codeforces - 831D. Office Keys - dp、二分+贪心

D. Office Keys 题目链接 分类:dp、二分、贪心 1.题意概述 一个坐标轴上有n个人,他们坐标分别为a[1...n]a[1...n],而且有k把钥匙坐标分别在b[1...k...

codeforces-486【C-贪心-思维】【D-树状DP】

题目链接:点击打开链接 A. Calculating Function time limit per test 1 second memory limit per test 25...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Codeforces_484D:Kindergarten(贪心/DP)
举报原因:
原因补充:

(最多只允许输入30个字)