HDU5696 区间的价值(分治/单调队列)

题目:定义区间的价值为这个区间内最大值和最小值的乘积。给定一个序列,求这个序列的每个长度的区间价值的最大值。所有测试数据严格随机。

思路:初学分治,感觉挺不好想出来,参考了一下别人的思路。因为要求每个区间最大值和最小值的乘积,先固定最小值,然后枚举最大值,由于确定了最小的一边,随着长度增加,区间的价值只可能变大,因此可以用短的区间值更新长的区间值。如果区间的最大价值不包含这个最小值,就以这个最小值为中点,同样策略递归地处理两边,在分治的过程中不断更新结果。

#include
using namespace std;
typedef long long LL;
int a[100005];
LL tmp[100005],ans[100005];
void solve(int l,int r){
    if(l>r)return;
    //cout<<"l "<
最初写这道题用的是单调队列的办法。

思路:用两个单调队列分别维护每个位置的最大值和最小值,就可以直接算啦,中间要注意剪枝。

#include
#include
#include
#include
#include
#define PI 3.1415926535
#define INF 0x3f3f3f3f
typedef long long ll;
const int N=100000+5;
int a[N];
int q1[N],q2[N];
int Scan()  {
    int res = 0, ch, flag = 0;
    if((ch = getchar()) == '-')             //判断正负
        flag = 1;
    else if(ch >= '0' && ch <= '9')           //得到完整的数
        res = ch - '0';
    while((ch = getchar()) >= '0' && ch <= '9' )
        res = res * 10 + ch - '0';
    return flag ? -res : res;
}
int main(){
    int n,l,r;
    ll ans=0,s,maxx,minn;
    while(~scanf("%d",&n)){
        l=r=1;
        for(int i=1;i<=n;++i){
            a[i]=Scan();//加了一个无关紧要的输入挂
            if(a[i]>a[l]){
                l=r=i;
                maxx=minn=a[i];
            }
        }
        ans=maxx*minn;
        printf("%lld\n",ans);//长度为1的区间直接输出最大值即可
        for(int i=2;i<=n;++i){
            if(l>1&&a[l-1]<=maxx&&a[l-1]>=minn){
                --l;
                printf("%lld\n",ans);
                continue;
            }//剪枝,上一次的结果可能也是这一次的结果
            if(r=minn){
                ++r;
                printf("%lld\n",ans);
                continue;
            }//剪枝
            int l1=0,l2=0,r1=-1,r2=-1;
            ans=0;
            for(int j=1;j<=n;++j){
                while(l1<=r1&&a[q1[r1]]<=a[j])--r1;
                q1[++r1]=j;//新元素入队列
                while(l2<=r2&&a[q2[r2]]>=a[j])--r2;
                q2[++r2]=j;
                while((j-q1[l1])>=i)++l1;//删除超出区间范围的队首
                while((j-q2[l2])>=i)++l2;
                if(jans){
                    maxx=a[q1[l1]];
                    minn=a[q2[l2]];
                    ans=s;
                    l=j-i+1;
                    r=j;
                }
            }
            printf("%lld\n",ans);
        }
    }
}



你可能感兴趣的:(分治)