首页 > 其他分享 >2019南昌网络赛 I. Max answer(DP或者单调栈+思维)

2019南昌网络赛 I. Max answer(DP或者单调栈+思维)

时间:2023-02-07 12:03:38浏览次数:44  
标签:max int Max ll tree 2019 ans answer sum


Alice has a magic array. She suggests that the value of a interval is equal to the sum of the values in the interval, multiplied by the smallest value in the interval.

Now she is planning to find the max value of the intervals in her array. Can you help her?

Input

First line contains an integer n(1 \le n \le 5 \times 10 ^5n(1≤n≤5×105).

Second line contains nn integers represent the array a (-10^5 \le a_i \le 10^5)a(−105≤ai≤105).

Output

One line contains an integer represent the answer of the array.

样例输入复制

5
1 2 3 4 5

样例输出复制

36

编辑代码

 

题意:

给你n个数字a[1~n](a[i]可能为负的),求任意一段区间和乘以区间数的最小值,求其最大。

分析:

我们枚举每一个a[i],寻找a[i]的可以满足的左右区间【l,r】。

l[i]左边第一个<h[i]的位置
r[i]右边第一个<h[i]的位置

运用单调栈或者DP都可以求,如果没有负数则就是:【POJ-2796】Feel Good

这题的难点是有负数,

如果h[i]>0,则直接求出h[i] * (sum[r[i]] - sum[l[i] - 1]);(因为正数的合法区间不会有负数)

如果h[i]<0,我们暴力寻找左边的sum[i]的最大值,寻找右边的sum[i]的最小值即可

单调栈做法

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll inf=1e18;
const int N = 500050;
ll h[N],sum[N];
ll l[N];//l[i]左边第一个<h[i]的位置
ll r[N];//r[i]右边第一个<h[i]的位置

int main()
{
int n;
stack<int> s;
while(~scanf("%d",&n))
{
if(n==0) return 0;
for(int i=1;i<=n;i++)
{
scanf("%lld",&h[i]);
sum[i]=sum[i-1]+h[i];
}

while(s.size()) s.pop();

for(int i=1;i<=n;i++)//保存单调递减栈(栈顶元素最小)
{
while(!s.empty()&&h[s.top()]>=h[i])
s.pop();

if(s.empty()) l[i]=1;
else l[i]=s.top()+1;
s.push(i);
}

while(s.size()) s.pop();

for(int i=n;i>=1;i--) //保存单调递减栈(栈顶元素最小)
{

while(!s.empty()&&h[s.top()]>=h[i])
s.pop();


if(s.empty()) r[i]=n;
else r[i]=s.top()-1;
s.push(i);
}

ll ans = -1e9;
for(int i = 1; i <= n; i++)
{
ll t;
if(h[i]>=0)
{
t = h[i] * (sum[r[i]] - sum[l[i] - 1]);
}
else
{
ll minn=inf,maxx=-inf;
for(int j=l[i]-1; j<i; j++)
{
maxx=max(sum[j],maxx);
}
for(int j=i; j<=r[i]; j++)
{
minn=min(sum[j],minn);
}
t=h[i]*(minn-maxx);
}
ans=max(t,ans);

}
printf("%lld\n", ans);
}
return 0;
}

 

DP

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <algorithm>
#include <queue>
#include <stack>
#include <map>
#include <vector>
using namespace std;
typedef long long ll;
const ll inf=1e18;
const int N=500005;
ll h[N];
ll l[N],r[N],sum[N];
//l[i]左边连续的>=a[i]位置
//r[i]右边连续的>=a[i]位置
int main()
{

int n;
while(scanf("%d",&n)!=-1)
{
if(n==0)
break;
stack<ll>s;
sum[0]=0;
for(int i=1; i<=n; i++)
{
scanf("%lld",&h[i]);
sum[i]+=sum[i-1]+h[i];
}
sum[n+1]=sum[n];
h[n+1]=0; ///注意这里
for(int i=1; i<=n+1; i++)
{
while(!s.empty()&&h[s.top()]>h[i])
{
r[s.top()]=i;
s.pop();
}

if(s.size()==0)
l[i]=i;
else
l[i]=s.top();
s.push(i);
}

ll ans = -1e9;
for(int i = 1; i <= n; i++)
{
ll t;
if(h[i]>=0)
{
t = h[i] * (sum[r[i]] - sum[l[i] - 1]);
cout<<r[i]<<" "<<l[i]<<endl;
}
else
{
ll minn=inf,maxx=-inf;
for(int j=l[i]-1; j<i; j++)
{
maxx=max(sum[j],maxx);

}
for(int j=i; j<=r[i]; j++)
{
minn=min(sum[j],minn);

}
t=h[i]*(minn-maxx);


}
ans=max(t,ans);

}
printf("%lld\n", ans);
}
return 0;
}

//DP+线段树

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll inf=1e18;
const int N = 5000050;
ll h[N],sum[N];
ll l[N];//l[i]左边第一个<h[i]的位置
ll r[N];//r[i]右边第一个<h[i]的位置
#define lson i<<1
#define rson i<<1|1
#define LS l,mid,lson
#define RS mid+1,r,rson
#define ll long long

ll b[N];
ll ans_sum,ans_max,ans_min;
struct node
{
int l,r;
ll max,min;
} tree[N<<2];

void pushup(int i)
{
tree[i].max=max(tree[lson].max,tree[rson].max);
tree[i].min=min(tree[lson].min,tree[rson].min);
}
//建立线段树
void build(int l,int r,int i)
{
tree[i].l = l;
tree[i].r = r;
if(l == r)
{
tree[i].max = sum[l];
tree[i].min = sum[l];

return;
}
int mid = (l+r)>>1;
build(LS);
build(RS);
pushup(i);
}


void query(int l,int r,int i)
{
//cout<<l<<" "<<r<<" "<<i<<endl;
if(l <= tree[i].l && tree[i].r <= r)
{
ans_max = max(ans_max,tree[i].max);
ans_min = min(ans_min,tree[i].min);
return ;
}
// pushdown(i);
int mid = (tree[i].l+tree[i].r)>>1;
if(l<=mid) query(l,r,lson);
if(r>mid) query(l,r,rson);
pushup(i);
}
stack<int> s;
int main()
{
int n;

while(~scanf("%d",&n))
{

for(int i=1; i<=n; i++)
{
scanf("%lld",&h[i]);
}

for(int i=1;i<=n;i++)
{
scanf("%lld",&b[i]);
sum[i]=sum[i-1]+b[i];
}
build(1,n,1);

while(s.size())
s.pop();

for(int i=1; i<=n; i++) //保存单调递减栈(栈顶元素最小)
{
while(!s.empty()&&h[s.top()]>=h[i])
s.pop();

if(s.empty())
l[i]=1;
else
l[i]=s.top()+1;
s.push(i);
}

while(s.size())
s.pop();

for(int i=n; i>=1; i--) //保存单调递减栈(栈顶元素最小)
{

while(!s.empty()&&h[s.top()]>=h[i])
s.pop();


if(s.empty())
r[i]=n;
else
r[i]=s.top()-1;
s.push(i);
}

ll ans = -1e18;
for(int i = 1; i <= n; i++)
{
ll t;
if(h[i]>=0)
{
t = h[i] * (sum[r[i]] - sum[l[i] - 1]);
}
else
{
ll minn=inf,maxx=-inf;
ans_max=-1e18;
query(l[i]-1,i-1,1);
maxx=ans_max;


ans_min=1e18;
query(i,r[i],1);
minn=ans_min;

t=h[i]*(minn-maxx);
}
ans=max(t,ans);

}
printf("%lld\n", ans);
}
return 0;
}

 

标签:max,int,Max,ll,tree,2019,ans,answer,sum
From: https://blog.51cto.com/u_14932227/6041851

相关文章

  • 2019/4/20、21训练博客
         一场中山大学的校赛,一场南昌大学网络赛.    两场都有遗憾,因为基本上前期还ok,但到后期就难以出题了,尤其是昨天的南昌大学网络赛,一道题已经房队......
  • 2019/4/18
     今天把最近打的51nod的比赛认为好题或者比赛的时候没做出来、没做到的题补了补,这些题,大部分都做过,看着眼熟,但依旧有的能出,有的不能出,害的好好下功夫,至少省赛前把三集题做......
  • mysql max_allowed_packet查询和修改
    ​mysql根据配置文件会限制server接受的数据包大小。有时候大的插入和更新会被max_allowed_packet参数限制掉,导致失败。查看目前配置  showVARIABLESlike......
  • 1710.maximum-units-on-a-truck 卡车上的最大单元数
    问题描述1710.卡车上的最大单元数解题思路根据每个箱子可以装载的单元数量从大到小对boxTypes排序,然后每次将单元数量最大的箱子填入卡车。使用快速选择算法可以将时间......
  • Maximize Win From Two Segments
    MaximizeWinFromTwoSegmentsTherearesomeprizesontheX-axis.Youaregivenanintegerarray prizePositions thatissortedinnon-decreasingorder,whe......
  • C# - VS2019 WINFRM应用程序开发报表
    简单报表我们可以通过label、textBox和PrintDialog来实现,但是一般在实际生产过程中,用户的报表需求一般都是比较复杂的。本篇主要记录对于传统中国式复杂报表的处理方法和......
  • 解决VS2019编译Qt报错:C3615 constexpr 函数“qCountLeadingZeroBits”不能生成常量表
    这个是Qt的BUG,要解决编译报错的问题,需要修改Qt安装目录下的一个文件:Qt\Qt5.9.5\5.9.5\msvc2015\include\QtCore\qalgorithms.h建议修改之前先保存一个副本,另外要根据编译......
  • P5572 [CmdOI2019]简单的数论题
    [CmdOI2019]简单的数论题题意即求:\[\sum_{i=1}^{n}\sum_{j=1}^{m}\varphi\left(\dfrac{\operatorname{lcm}(i,j)}{\gcd(i,j)}\rig......
  • java实现oracle和mysql的group by分组功能|同时具备max()/min()/sum()/case when 函数
    一、前言oracle和mysql的groupby分组功能大家应该清楚,那如何使用java实现同样的功能呢比如下面这个表idnameagemathEnglish10yujianlin2092.5103ww841025201026110363103......
  • 2019年7月31 日训练日记
    早上把昨晚打cf没做出来的题讨论了一下,发现我们原来理解的题意完全不一样,然后看了看别人的代码,发现思路特别巧妙。上午把vjudge的题补完了,然后又把cf可以做没做出来的题补完......