"尚学堂杯"哈尔滨理工大学第七届程序设计竞赛 B Blind Father(单调栈)+G Great Atm(二进制)

B、题目链接:http://acm.hrbust.edu.cn/index.php?m=ProblemSet&a=showProblem&problem_id=2326

思路:要求一段连续区间内的最大长方形面积,我们可以用dp[i]数组表示长度为i的区间的最大长方形面积,每次更新数组,直到求出最大值。重点是如何无更新呢???我们用a[i]表示这一段区间的最大值,向两边更新区间的最小值,然后要求的面积就是min*区间长度,更新完找个最大的就是答案。

可能是这道题的数据比较水,HDU 1506基本上是一样的题,暴力直接找会超时,还需要用到单调栈,时间复杂度是O(n).

CODE1:(暴力)

#include<stdio.h>
#include<stdlib.h>
#include<iostream>
#include<algorithm>
#include<math.h>
#include<map>
#include<queue>
#include<stack>
#include<string.h>
typedef long long LL;
using namespace std;
#define INF 0x3f3f3f3f
const int maxn=100005;
const double eps=0.0001;
LL a[maxn],dp[maxn];//dp[i]表示区间长度为i时能得到的最大值
int main()
{
    int n;
    while(~scanf("%d",&n))
    {
        memset(dp,0,sizeof(dp));
        for(int i=1;i<=n;i++)
            scanf("%lld",&a[i]);
        LL maxx=0;
        for(int i=1;i<=n;i++)
        {
            dp[1]=max(dp[1],a[i]);
            LL minn=a[i];
            int l,r;
            l=r=i;
            while(true)
            {
                if(r-l+1>=n)//如果找完了,跳出
                    break;
                if(l!=1&&(r==n||a[l-1]>a[r+1]))
                    minn=min(minn,a[--l]);
                else
                    minn=min(minn,a[++r]);
                if(a[i]<a[l]||a[i]<a[r])//如果a[i]不是这段区间的最大值,跳出
                    break;
                dp[r-l+1]=max(dp[r-l+1],minn*(r-l+1));
            }
        }
        for(int i=1;i<=n;i++)
            maxx=max(maxx,dp[i]);
        printf("%lld\n",maxx);
    }
    return 0;
}

CODE2:单调栈

#include<stdio.h>
#include<stdlib.h>
#include<iostream>
#include<algorithm>
#include<math.h>
#include<map>
#include<queue>
#include<stack>
#include<string.h>
typedef long long LL;
using namespace std;
#define INF 0x3f3f3f3f
const int maxn=100005;
const double eps=0.0001;
struct node
{
    LL h,w;
} c[maxn];
stack<node>s;
int main()
{
    int n;
    while(~scanf("%d",&n))
    {
        LL ans=0,cnt=0;
        while(!s.empty())
            s.pop();
        c[0].h=0;
        c[0].w=0;
        s.push(c[0]);
        for(int i=1; i<=n; i++)
        {
            scanf("%d",&c[i].h);
            c[i].w=1;
        }
        for(int i=1; i<=n; i++)
        {
            if(c[i].h>s.top().h)
            {
                c[i].w=1;
                s.push(c[i]);
            }
            else
            {
                cnt=0;
                while(!s.empty()&&s.top().h>c[i].h)
                {
                    ans=max(ans,(cnt+s.top().w)*s.top().h);
                    cnt+=s.top().w;
                    s.pop();
                }
                c[i].w=cnt+1;
                s.push(c[i]);
            }
        }
        cnt=0;
        while(!s.empty())
        {
            ans=max(ans,(cnt+s.top().w)*s.top().h);
            cnt+=s.top().w;
            s.pop();
        }
        printf("%lld\n",ans);
    }
    return 0;
}

这道题和HDU 5696区间的价值类似(题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5696),区间价值 这道题就是求区间1~n内,区间长度为i的最大值和最小值的最大乘积,思路基本上是一样,更新的时候是:

dp[r-l+1]=max(dp[r-l+1],minn*a[i]); 前一段时间刚做过这道题,还有点印象,不过还是卡了一会。。。


G、题目链接:http://acm.hrbust.edu.cn/index.php?m=ProblemSet&a=showProblem&problem_id=2331

思路:与、或、异或都与二进制有关,我们可以从这个角度出发去解决问题。
当时题面改了之后没看太懂题目,去讨论区看了一下才测地明白题意,就是从[0,m]之间找出一个数,使它按给定的顺序运算下去结果最大,输出最大的结果,看明白题意之后就暴力写了一发,跑出来样例,并没有敢交,结果肯定会超时,然后就想了好一会,想到二进制,用小于m的2的i次方去找结果,过了样例,直接就交了,WA,呜呜~~(>_<)~~~~,不知道为啥,这时比赛已经快结束了,抱着试一试的心态又判了2^i-1,2^i+1(结果不对,肯定是判的 少 了,毕竟吧【0,m】个数变成了几个数,就多判了几个),对结果找一个最大的,竟然过了,好开心,不知道原理是什么,就这样神奇的过了,多猜猜还是有好处的,嘿嘿,,不过还是要自己理解。

CODE:

#include<stdio.h>
#include<stdlib.h>
#include<iostream>
#include<algorithm>
#include<math.h>
#include<map>
#include<queue>
#include<stack>
#include<string.h>
typedef long long LL;
using namespace std;
#define INF 0x3f3f3f3f
const int maxn=100005;
const double eps=0.0001;
struct node
{
    char s[15];
    int x;
}c[maxn];
int a[32];
void init()
{
    a[0]=1;
    for(int i=1;i<32;i++)
        a[i]=a[i-1]*2;
}
int main()
{
    int n,m;
    init();
    while(~scanf("%d%d",&n,&m))
    {
        int maxx=0;
        for(int i=0;i<n;i++)
            scanf("%s%d",c[i].s,&c[i].x);
        for(int i=0;a[i]<=m;i++)
        {
            int xx=a[i],yy=a[i]-1,zz=a[i]+1;
            for(int j=0;j<n;j++)
            {
                //cout<<c[j].s<<" "<<c[j].x<<endl;
                if(c[j].s[0]=='A')
                {
                    xx=xx&c[j].x;
                    yy=yy&c[j].x;
                    zz=zz&c[j].x;
                }
                else if(c[j].s[0]=='O')
                {
                    xx=xx|c[j].x;
                    yy=yy|c[j].x;
                    zz=zz|c[j].x;
                }
                else if(c[j].s[0]=='X')
                {
                    xx=xx^c[j].x;
                    yy=yy^c[j].x;
                    zz=zz^c[j].x;
                }
            }
            maxx=max(maxx,max(xx,max(yy,zz)));
        }
        printf("%d\n",maxx);
    }
    return 0;
}
经过了天梯赛,慢慢开始学会了在没有思路的情况下,凭着感觉大胆的去猜,这样思路打开的才会更快。每天进步一点点,就会有很大的飞跃。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值