标签:tar 输出 pac pre span problem .com date unsigned
题意:
给定一个区间,要求找出一个子区间使得这个区间的最小值乘以区间上所有数的和最大,输出和,与这个区间的左右边界。
分析:
很明显这个最优子区间的最小值,一定是总区间上的某个值。所以我们就枚举每个值,利用单调栈找到每个值对应的子区间的边界,在用树状数组求出这个子区间所有数的和,取n次结果中的最大值即可。
代码:
#include <stack> #include <stdio.h> #include <string.h> #include <iostream> #include <algorithm> using namespace std; #define ll long long #define ull unsigned long long #define cls(x) memset(x,0,sizeof(x)) #define clslow(x) memset(x,-1,sizeof(x)) const int maxn=1e5+100; int n; stack<int>st; ll bit[maxn]; int a[maxn],L[maxn],R[maxn]; int lowbit(int x) { return x&-x; } void update(int x,int add) { while(x<=n) { bit[x]+=add; x+=lowbit(x); } } ll sum(int x) { ll res=0; while(x>0) { res+=bit[x]; x-=lowbit(x); } return res; } //树状数组求区间和 ll query(int x,int y) { return sum(y)-sum(x-1); } //单调栈找出每个值对应的子区间的边界 void solve() { while(!st.empty()) st.pop(); for(int i=1;i<=n;i++){ while(st.size()&&a[st.top()]>=a[i]) st.pop(); if(st.empty()) L[i]=0; else L[i]=st.top(); st.push(i); } while(!st.empty()) st.pop(); for(int i=n;i>=1;i--){ while(st.size()&&a[st.top()]>=a[i]) st.pop(); if(st.empty()) R[i]=n+1; else R[i]=st.top(); st.push(i); } } void print() { int l,r; ll ans=-1; for(int i=1;i<=n;i++){ ll val=query(L[i]+1,R[i]-1)*a[i]; if(ans<val){ ans=val; l=L[i]+1; r=R[i]-1; } } printf("%lld\n",ans); printf("%d %d\n",l,r); } int main() { // freopen("in.txt","r",stdin); while(scanf("%d",&n)!=EOF) { cls(bit); for(int i=1;i<=n;i++){ scanf("%d",&a[i]); update(i,a[i]); } solve(); print(); } return 0; }
标签:tar 输出 pac pre span problem .com date unsigned
原文地址:https://www.cnblogs.com/shutdown113/p/9381378.html