Mooo

【题目描述】

  有 N 个能量发射站排成一行,每个发射站i都有不相同的高度 Hi,并能向两边(当然两端的只能向一边)同时发射能量值为 Vi 的能量,并且发出的能量只被两边最近的且比它高的发射站接收。

  显然每个发射站有可能接收 0 或 1 或 2 个其它发射站发来的能量,特别是为了安全,它受到的能量总和是我们很关心的。由于数据很多,请你帮助我们计算出接受了最多能量的发射站接受的能量是多少。

【数据范围】

1 <= N <= 50,000

1 <= hi <= 2,000,000,000

1 <= vi <= 10,000

【输入格式】

第1行: 一个整数 N

第2..N+1行:第 i+1 行有2个整数 Hi Vi,表示第i个发射站的高和发射的能量值。

【输出格式】

一行:一个发射站接收到的最大能量值。

【样例输入】

3
4 2
3 5
6 10

【样例输出】

7


蒟蒻表示还是不会

怎么办呢?

随机枚举信号塔求此塔的接收值+卡时

。。。。。。

然后居然又A了

RP已败光。。。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<ctime>
#include<cstdlib>
using namespace std;
int m;
int z,ans;
struct self{int x,y;}s[50555]; //high->x  power->y
int a,b,c;
int tall,num;
bool flag[50555];

void eixt()
{
    cout<<z<<'\n';
}

void work(int i)
{
    ans=0;
    int a,b,lt,rt;
    lt=rt=0;
    for(a=i-1;a>=1;a--)
    {
        if(s[a].x>=s[i].x)break;
        if(s[a].x>=lt)
        {
            ans+=s[a].y;
            lt=s[a].x;
        }
    }
    
    for(b=i+1;b<=m;b++)
    {
        if(s[b].x>=s[i].x)break;
        if(s[b].x>rt)
        {
            ans+=s[b].y;
            rt=s[b].x;
        }
    }
    z=max(z,ans);
}
        
int main()
{
    freopen("mooo.in","r",stdin);freopen("mooo.out","w",stdout);
    scanf("%d",&m);
    for(a=1;a<=m;a++)
    {
        scanf("%d%d",&s[a].x,&s[a].y);
        if(s[a].x>tall)
        {
            tall=s[a].x;
            num=a;
        }
    }
    
    flag[num]=1;
    work(num);
    
    while((double)clock()/CLOCKS_PER_SEC<=0.91)
    {
        ans=0;
        a=(rand()+rand())%m+1;
        while(flag[a])
        {
            a=(rand()+rand())%m+1;
            if((double)clock()/CLOCKS_PER_SEC>=0.93)
            {
                eixt();
                return 0;
            }
        }
        flag[a]=1;
        work(a);
    }
    eixt();
    return 0;
}



正解是单调队列或者单调栈吧

还要ORZ XPF大神


我们可以先考虑向左发射信号

再考虑向右发射信号


用一个栈维护i前(或后)的第一个比h[i]高的塔的编号

先考虑向左发射的情况

对于栈顶top对应的ht和wt

如果当前i站的hi=>ht则需要找到第一个比hi大的ht 需要top-- 

因为stack的push是从前向后的 所以第一个满足ht>hi的top肯定是i前面第一个比h大的站

l[stack[top]]+=s[i].w; 同时i进栈


如果当前i站的hi<ht 表示i前的最低高度大于hi  t站可以接收到i的信号

此时只需将i进栈 l[stack[top]]+=s[i].w;


正着一遍 反着一遍 ans=max(ans,l[i]+r[i]);

#include<iostream>
#include<cstdio>
using namespace std;
const int lim=50555;
int stack[lim];
int top;

int l[lim],r[lim];

struct self{int h,w;}s[lim];
int m,a,b,c;

void left()
{
	int a,b;
	top=1;
	stack[1]=1;
	for(a=2;a<=m;a++)
	{
		if(s[stack[top]].h>s[a].h)
		{
			l[stack[top]]+=s[a].w;
			top++;
			stack[top]=a;
		}
		
		else
		{
			while(s[stack[top]].h<=s[a].h&&top>0)top--;
			if(top>=1)l[stack[top]]+=s[a].w;
			top++;
			stack[top]=a;
		}
	}
}

void right()
{
	int a,b;
	top=1;
	stack[1]=m;
	for(a=m-1;a>=1;a--)
	{
		if(s[stack[top]].h>s[a].h)
		{
			l[stack[top]]+=s[a].w;
			top++;
			stack[top]=a;
		}
		
		else
		{
			while(s[stack[top]].h<=s[a].h&&top>0)top--;
			if(top>=1)l[stack[top]]+=s[a].w;
			top++;
			stack[top]=a;
		}
	}
}

void print()
{
	int a,ans=0;
	for(a=1;a<=m;a++)ans=max(ans,l[a]+r[a]);
	cout<<ans<<'\n';
}

int main()
{
	freopen("mooo.in","r",stdin);freopen("mooo.out","w",stdout);
	scanf("%d",&m);
	for(a=1;a<=m;a++)scanf("%d%d",&s[a].h,&s[a].w);
	
	left();right();
	
	print();
	return 0;
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值