UVA 1619 - Feel Good(dp 求区间最小值 附加RMQ)(区间最小值优化)

看了刘汝佳的 翻译 我也是醉了。 原题明明数据是 0- 100000   书上翻译给了个 正整数。。


自己这个题很久之前就看了。 想了很久没想出来。 今天在看线段树。 看到了 RMQ,  就是求区间最小值得。 然后自己就回头又看这个题。 


数据量太大了。 用 RMQ 是没法做出来的。  然后自己只能去网上找了题解,


对于每一个数据  v【i】  都可以找到 它是某个区间的 最小值,  左短点是  l【】  右短点是  r【】


提前预处理 sum【i】 前i项和  那么  区间的  结果就好求了。   关键的地方就是 在  确定 l  和 r 的问题上


别人的思路确实很好。  比如 一组数据  6 5 4 3 2        3的左端点 求出来了 是  1    那么在 求 2 的左端点时 因为 3 比 2大 那么 3的左端点一定是 2的左端点


这样直接赋值给2  然后 再去求3的左端点就好了。 相比以前的 挨个遍历要快很多。 同理 右端点一样处理


#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <string>
#include <map>
#include <vector>
#include <set>
#include <queue>
#include <stack>
#include <cctype>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#define maxn 1000010
#define INF 1<<30
ll sum[maxn];
int v[maxn],l[maxn],r[maxn];
int main (){
    int n;
    int kase = 0;
    while(scanf("%d",&n) != EOF){
        sum[0] = 0;
        if(kase)
            printf("\n");
        kase++;
        for(int i = 1; i <= n; i++){
            scanf("%lld",&v[i]);
            sum[i] = sum[i-1] + v[i];
            l[i] = i;
            r[i] = i;
        }
        for(int i = 1; i <= n; i++){
            if(v[i] > 0)
            while(v[l[i]-1] >= v[i]){
                l[i] = l[l[i]-1];
            }
        }
        for(int i = n; i >= 1; i--){
            if(v[i] > 0)
            while(v[r[i] + 1] >= v[i]){
                r[i] = r[r[i] + 1];
            }
        }
        ll ans = 0;
        int ll = 1, rr = 1;
        long long nu;
        for(int i = 1; i <= n; i++){
            if(v[i] > 0){
                nu = v[i] *(sum[r[i]] - sum[l[i] - 1]);
                if(nu > ans){
                    ans = nu;
                    ll = l[i];
                    rr = r[i];
                }
                else if(nu == ans){
                    if(rr - ll == r[i] - l[i] && l[i] < ll)
                        ll = l[i],rr = r[i];
                }
            }
        }
        printf("%lld\n%d %d\n",ans,ll,rr);
    }
    return 0;
}


再说一下 RMQ  


RMQ  就比较简单了。  在一个区间内。  把它分成两部分。 分别取这两部分的最小值就好了。


它是用二维数组 d【i】【j】 来表示的 从  i  到 j 的最小值。 那么 像上面那样 100000 最大的数据量 肯定是 开不开的。  只能用上面的方法吧


具体代码实现  训练之南  P198


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值