题意:求一段连续子序列al,…,ar,使(al+…+ar)*min{al,…ar}尽量大.
个人感想:明显的RMQ+前缀和,但是UVA有点坑,题目上的意思是pecial judge,可是输出必须得区间最小的,而且最左边的,我用线段树做的RMQ直接wa,我只能用直接的RMQ了…还有一个输出是个坑点,否则就PE
分析:RMQ(用于记录最小值的位置)+前缀和
代码:
/* Author:GavinjouElephant
* Title:
* Number:
* main meanning:
*
*
*
*/
//#define OUT
#include <iostream>
using namespace std;
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <sstream>
#include <cctype>
#include <vector>
#include <set>
#include <cstdlib>
#include <map>
#include <queue>
//#include<initializer_list>
//#include <windows.h>
//#include <fstream>
//#include <conio.h>
#define MaxN 0x7fffffff
#define MinN -0x7fffffff
#define Clear(x) memset(x,0,sizeof(x))
const int INF=0x3f3f3f3f;
const int maxn=1e5+10;
long long a[maxn];
long long Sum[maxn];
int minsum[maxn][18];
long long M;
int T;
int L;
int R;
int p;
void RMQ(int num)
{
for(int j=1;j<18;j++)
{
for(int i=1;i<=num;i++)
{
if(i+(1<<j)-1<=num)
{
if(a[minsum[i][j-1]]<a[minsum[i+(1<<(j-1))][j-1]])
{
minsum[i][j]=minsum[i][j-1];
}
else
{
minsum[i][j]=minsum[i+(1<<(j-1))][j-1];
}
}
}
}
}
void init()
{
Sum[0]=0;
M=-INF;
}
void solve(int l,int r)
{
if(r<l)return;
int k=(int)(log2(r-l+1));
int p;
//找到整段区间的最小值的位置.
if(a[minsum[l][k]]<a[minsum[r-(1<<k)+1][k]])
{
p=minsum[l][k];
}
else
{
p=minsum[r-(1<<k)+1][k];
}
//计算值
long long ans=a[p]*(Sum[r]-Sum[l-1]);
//找最小值和区间
if(ans>M||ans==M)
{
if(ans>M)
{
M=ans;
L=l;
R=r;
}
else
{
if((R-L)>(r-l)||((R-L)==(r-l)&&l<L))
{
L=l;
R=r;
}
}
}
solve(l,p-1);
solve(p+1,r);
}
int main()
{
#ifdef OUT
freopen("coco.txt","r",stdin);
freopen("lala.txt","w",stdout);
#endif
bool qwe = false;
while(scanf("%d",&T)!=EOF)
{
init();
for(int i=1;i<=T;i++)
{
cin>>a[i];
Sum[i]=Sum[i-1]+a[i];
minsum[i][0]=i;
}
RMQ(T);
solve(1,T);
if (qwe) printf("\n");//这是个坑点..一点意思也没有..
else qwe = true;
cout<<M<<endl;
cout<<L<<" "<<R<<endl;
}
return 0;
}