http://acm.hdu.edu.cn/showproblem.php?pid=5696
后几个写法慢慢写。
开始写了一个暴力,一直tle,应该是边界没处理好。尴尬。。
我们可以确定一种情况。
除却相等使用的情况。最小的那个数作为区间中的最小数,越少越好,而最大数,越多越好
两个贪心策略:尽可能的用最大这个数。(枚举区间情况)
2 同一个 最大*最小 可以被很多长度区间所利用(包含区间情况)
。暴力 虽然是枚举的最大值,但是这个最大值是可以被好几个 区间所利用的,。所以可以。
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
using namespace std;
typedef long long ll;
const int maxn=100050;
ll dp[maxn];
ll a[maxn];
int main()
{ int m;
while(~scanf("%d",&m)){
for(int i=1;i<=m;i++)
scanf("%lld",&a[i]);
memset(dp,0,sizeof(dp));
for(int i=1;i<=m;i++){
int l=i;
int r=i;
dp[1]=max(dp[1],a[i]*a[i]);
ll min1=a[i];
while(1){
if(a[l]>a[i]||a[r]>a[i]) break;
if((r-l+1)==m) break;
if((a[l-1]>a[r+1]||(r==m))&&1!=l)
{min1=min(a[l-1],min1);l--;}
else
{min1=min(a[r+1],min1);r++;}
dp[r-l+1]=max(dp[r-l+1],a[i]*min1);
}
}
for(int i=1;i<=m;i++)
printf("%lld\n",dp[i]);
}
return 0;
}
但是单调栈我就要说一下了
这个是用的单调栈+rmq(st算法倍增)来弄得。
特别注明一下 单调栈,
维护一个单调递增的栈,用来确定i为最小来确定的区间,这个可以当做模板使用。可以自己想一下。
先维护每个i为最小的区间,然后在这个区间内用rmq求极大值,相乘就行了,注意 开头我说的第二项原理,并且第二项原理是可以从1用到m的。自己一下就明白了。
那为什么这个题不用枚举每一个为最大值,然后rmq求极小值,然后在正常搞呢。
我试着写了一下,mb竟然不对。大概是因为 最大值只能利用一次。
(恩,最大值被多次利用有两种情况,一种是第一种计算区间的时候,第二种是区间包含的情况。)
我说的不太明白,慢慢我会补几张图的,
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#include<vector>
#include <ctime>
#include<queue>
#include<set>
#include<map>
#include<cmath>
#include <bits/stdc++.h>
typedef long long ll;
/*我们可以确定一种情况。
除却相等使用的情况。最小的那个数作为区间中的最小数,越少越好,而最大数,越多越好
两个贪心策略:尽可能的用最大这个数。
2 同一个 最大*最小 可以被很多长度区间所利用
*/
using namespace std;
const int maxn=100005;
int l[maxn];
int r[maxn];
stack<pair<int,ll> >q;
ll a[maxn];
ll FMax[maxn][20];
int m;
ll dp[maxn];
void Init(){
int i,j;
for(i=1;i<=m;i++)
FMax[i][0]=a[i];//以i为起点,长度为1的区间,初始值为a[i];
for(i=1;(1<<i)<=m;i++){ //区间慢慢扩增
for(j=1;j+(1<<i)-1<=m;j++){ //区间起点,
// FMin[j][i]=min(FMin[j][i-1],FMin[j+(1<<(i-1))][i-1]);
FMax[j][i]=max(FMax[j][i-1],FMax[j+(1<<(i-1))][i-1]);
}
}
}
ll Query(int l,int r){
int k=(int)(log(r-l+1)/log(2));
return max(FMax[l][k],FMax[r-(1<<k)+1][k]);//0(1)的查询
}
int main(){
while(~scanf("%d",&m)){
memset(dp,0,sizeof(dp));
memset(FMax,0,sizeof(FMax));
memset(a,0,sizeof(a));
memset(l,0,sizeof(l));
memset(r,0,sizeof(r));
for(int i=1;i<=m;i++){
scanf("%lld",&a[i]);
}
while(!q.empty())
q.pop();
q.push(make_pair(0,0));
for(int i=1;i<=m;i++){
while(!q.empty()){
pair<int,ll> u=q.top();
if(u.second>a[i]){
r[u.first]=i-1;
q.pop();
}
else { q.push(make_pair(i,a[i]));
break;
}
}
}
while(!q.empty()){
pair<int,ll>u=q.top();
r[u.first]=m;
q.pop();
}
q.push(make_pair(0,0));
for(int i=m;i>=1;i--){
while(!q.empty()){
pair<int,ll> u=q.top();
if(u.second>a[i]){
l[u.first]=i+1;
q.pop();
}
else { q.push(make_pair(i,a[i]));
break;
}
}
}
while(!q.empty()){
pair<int,ll>u=q.top();
l[u.first]=1;
q.pop();
}
/*for(int i=1;i<=m;i++){
printf("%d %d\n",l[i],r[i]);
}*/
Init();
for(int i=1;i<=m;i++){
int len=r[i]-l[i]+1;
dp[len]=max(dp[len],Query(l[i],r[i])*a[i]);
}
dp[m+1]=0;
ll ans=0;
for(int i=m;i>=1;i--){
ans=max(dp[i+1],ans);
dp[i]=max(dp[i],ans);
}
for(int i=1;i<=m;i++){
printf("%lld\n",dp[i]);
}
}
return 0;
}
最后的写法是 分治。有空多看
#include<iostream>
#include<cstdio>
#include<cstring>
#define LL long long
using namespace std;
const int MAXN = 1e5+5;
LL a[MAXN],temp[MAXN],ans[MAXN];
void solve(int l,int r)
{
if(l>r)
return ;
int p=0;
for(int i = l;i<=r;i++)
{
if(!p||a[i]<a[p])
p = i;
}
int w = r-l+1;
for(int i = 1;i<=w;i++)
temp[i] = 0;
LL pre = 0;
//遍历一遍区间获得他们的最大区间值
for(int i = p-1;i>=l;i--)
{
if(temp[p-i+1]<max(pre,(LL)a[p]*a[i]))
{
temp[p-i+1] = max(pre,(LL)a[p]*a[i]);
//因为最小值固定下来了,也就是看最大值哪个大
//短区间的值可以给长区间做更新(也就是短区间的最大值更大)
pre=temp[p-i+1];
}
}
pre = 0;
for(int i = p+1;i<=r;i++)
{
if(temp[i-p+1]<max(pre,(LL)a[p]*a[i]))
{
temp[i-p+1] = max(pre,(LL)a[p]*a[i]);
pre = temp[i-p+1];
}
}
ans[1] = max(ans[1],a[p]*a[p]);
pre = 0;
//整体的区间长度的最大价值更新操作
for(int i = 2;i<=w;i++)
{
if(ans[i]<max(pre,temp[i]))
{
ans[i]=max(pre,temp[i]);
}
pre = max(pre,temp[i]);
}
solve(l,p-1);
solve(p+1,r);
}
int main()
{
freopen("in2.txt","r",stdin);
//freopen("out1.txt","w",stdout);
int n;
while(~scanf("%d",&n))
{
memset(ans,0,sizeof(ans));
for(int i = 0;i<MAXN;i++)
temp[i] = 0;
for(int i =1;i<=n;i++)
scanf("%I64d",&a[i]);
solve(1,n);
for(int i = 1;i<=n;i++)
{
printf("%I64d\n",ans[i]);
}
}
return 0;
}