习题 8-18 UVA - 1619 Feel Good 感觉不错 (容斥定理)

大体题意:

给你一个长度为n (n <= 100000)的正整数序列ai,求出一段连续子序列a1,,ar 使得 (a1 + a2+ a3 +... ar) * min (a1,a2,a3,,,,ar)尽量大 如果多解任意输出一个!

思路:

思路是比较清晰的,就是有坑:

用sum[i]表示 1 ...i 的和,l[i],r[i],分别表示以第 i 个数字为最小值所能扩展的最左端和最右端!

最后遍历i  更新ans

ll ans = a[i] * (sum[r[i]] - sum[l[i]-1]);

取个最大值即可!

求l 和r 数组还不能暴力求,这样会超时。

        for (int i = 1; i <= n; ++i)
            while(a[l[i]-1] >= a[i])l[i] = l[l[i]-1];

这样求得话  因为遍历到i 时,l[i] 肯定等于i 的,所以当i的位置前一个数值大于等于 第i 个数值时,第i个数值就应该扩展到  第i个数 前一个位置的数 所能扩展到的位置!

r数组 同理。

最后是更新ans

记录下标时 pl 记录l  pr 记录r   他们必须初始化,因为刚上来可能是0嘛! 数据问题!

然后MAX 初始化为0 在与ans 不断比较就可以了

 

#include<cstdio>
#include<cstring>
#include<algorithm>
#define fin freopen("cin.txt","r",stdin);
#define fout freopen("out.txt","w",stdout);
using namespace std;
typedef long long ll;
const int INF = 1e9+5;
const int maxn = 100000 + 10;
int n,a[maxn];
ll sum[maxn];
int pl,pr,cnt;
int l[maxn],r[maxn];
int main(){
//    fin;
    while(scanf("%d",&n) == 1){
        for (int i = 1; i <= n; ++i){
            scanf("%d",&a[i]);
            sum[i] = sum[i-1] + a[i];
            l[i] = r[i] = i;
        }
        a[0] = -INF;
        a[n+1] = -INF;
        for (int i = 1; i <= n; ++i)
            while(a[l[i]-1] >= a[i])l[i] = l[l[i]-1];
        for (int i = n; i >= 1; --i)
            while(a[r[i]+1] >= a[i])r[i] = r[r[i]+1];
//        printf("start\n");
//        for (int i = 1; i <= n; ++i)printf("%d ",a[i]);
//        printf("\n");
//        for (int i = 1; i <= n; ++i)printf("%d ",l[i]);
//        printf("\n=\n");
//        for (int i = 1; i <= n; ++i)printf("%d ",r[i]);
//        printf("\n");
        ll MAX = 0;
        pl = pr = 1;
        for (int i = 1; i <= n; ++i){
            ll ans = a[i] * (sum[r[i]] - sum[l[i]-1]);
            if (ans > MAX){
//                printf("%lld\n",ans);
                MAX = ans;
                pl = l[i];
                pr = r[i];
            }
        }
        if (cnt++)printf("\n");
        printf("%lld\n%d %d\n",MAX,pl,pr);
    }
    return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值