zoukankan      html  css  js  c++  java
  • CF484D Kindergarten

    CF484D Kindergarten

    洛谷传送门

    题意翻译

    有一组数,你要把他分成若干连续段。每一段的值,定义为这一段 数中最大值与最小值的差。 求一种分法,使得这若干段的值的和最大。 N < 1e6, a[i] < 1e9。


    题解:

    正解:贪心+DP。

    贪心策略:一定是单调连续串(递增递减都可以)使得最终加出来的和最优。否则都可以拆成单调串来处理。

    然后第一感觉不需要DP,直接模拟然后累加就可以。但是发现不太对劲,因为对于序列的峰值和谷值来讲,我们不知道把它归属于前面最优还是后面更优。所以需要一个DP来保证每次决策的局部最优性,从而递推得出全局最优性。

    显然,需要记录前方的峰值或谷值的位置,这里记为pos。

    然后设(dp[i])表示前i个数所获得的最大价值。

    那么转移方程就是:

    [dp[i]=max(dp[pos]+|a[i]-a[pos+1]|,dp[pos-1]+|a[pos]-a[i]|) ]

    也就是把pos值分别归属于前面的串和自己的贡献取较大。

    然后再更新pos值即可。更新pos值的过程只需要用当前数前后各一个数来判就可以。

    代码:

    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    const int maxn=1e6+6;
    ll n,a[maxn],dp[maxn],pos=1;
    bool check(ll x)
    {
    	return (a[x]>=a[x-1]&&a[x]>=a[x+1])||(a[x]<=a[x-1]&&a[x]<=a[x+1]);
    }
    int main()
    {
    	scanf("%lld",&n);
    	for(int i=1;i<=n;i++)
    		scanf("%lld",&a[i]);
    	for(int i=2;i<=n;i++)
    	{
    		dp[i]=max(dp[pos]+abs(a[i]-a[pos+1]),dp[pos-1]+abs(a[pos]-a[i]));
    		pos=check(i)?i:pos;
    	}
    	printf("%lld
    ",dp[n]);
    	return 0;
    }
    
  • 相关阅读:
    安装项目管理工具 SVN+Redmine
    jquery validate
    NHibernate集合映射中的set, list, map, bag, array
    NHibernate执行原始SQL代码的方法小结 .
    一个简单的存储过程
    修改Project中的表名及字段名
    用代码修改类名
    实现Pick和Reigister
    转移单的装运和收货
    库存维度检查
  • 原文地址:https://www.cnblogs.com/fusiwei/p/14034374.html
Copyright © 2011-2022 走看看