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)枚举时来尝试补全并更新最后的答案.

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/OMRailgun/article/details/53997817

Codeforces Round #298 (Div. 2) C Polycarpus' Dice

【题目】点击打开链接 【题意】输入n,A,一共有n个色子,他们向上的点数和为A,然后给出n个数,分别代表每个色子最大的掷出点数,要求出每个色子有几个值是不可能掷出的。 【解题思路】对于一个色子...
  • just_sort
  • just_sort
  • 2016-06-24 22:48:10
  • 255

【二分】划分数列

划分数列(seq.pas/c/cpp) 【题目描述】 给你一个有n个元素的数列,要求把它划分成k段,使每段元素和的最大值最小 【输入格式】 第一行两个正整数n,k 第二行为此数列ai 【输...
  • wu_yihao
  • wu_yihao
  • 2012-08-15 20:27:15
  • 556

【HDU3530】【单调队列(双)】Subsequence 【长度为n的数列,求最长子区间的长度,使得区间的最大值与最小值的差满足一个范围】

传送门:HDU 3530 Subsequence 描述: Subsequence Time Limit: 2000/1000 MS (Java/Others)    Memory Lim...
  • guhaiteng
  • guhaiteng
  • 2016-10-08 15:57:01
  • 1613

codeforces 484D kindergarten

刚开始没细读题目,直接快排后
  • u014436243
  • u014436243
  • 2014-11-15 12:22:28
  • 283

CodeForces 484 D.Kindergarten(dp)

Description 给出一个长度为n的序列a[i],先要将该序列分成若干连续子段,每一段的价值定义为该段极差,问最大总价值是多少 Input 第一行一整数n表示序列长度,之后输入n个整数a[...
  • V5ZSQ
  • V5ZSQ
  • 2017-04-10 17:04:48
  • 227

Codeforces 484D Kindergarten(dp)

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

【codeforces 484D】【DP】Kindergarten

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

Codeforces_484D:Kindergarten(贪心/DP)

题目大意是说给定n个数字,要求你把它分成若干段连续的数列,每段有个贡献值,为这段数列中最大值与最小值之差,然后整个数列的贡献值为每段的贡献值之和,现在让你求该数列的最大贡献值. 由简单分析,便可得出每...
  • OMRailgun
  • OMRailgun
  • 2017-01-03 20:59:43
  • 233

[Codeforces 484D] Kindergarten (DP + 树状数组优化)

Codeforces - 484D 给定一个长度为 N 的数列,可以将连续的一段分成一组 每组的价值为组内最大值减最小值,数列的价值为所有组的价值和 问整个数列的价值的最大值 很容易想...
  • u012015746
  • u012015746
  • 2017-01-21 16:39:45
  • 91

ZOJ 3715 Kindergarten Election 幼儿园的选举(枚举贪心)

点击打开链接
  • Dinivity123
  • Dinivity123
  • 2014-04-17 11:20:22
  • 1416
收藏助手
不良信息举报
您举报文章:Codeforces_484D:Kindergarten(贪心/DP)
举报原因:
原因补充:

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