HDU 3193 Find the hotel(RMQ,需要转换,巧妙二维变一维)

题意:

给定n个旅馆的pd两个属性,然后输出所有的目的旅馆。如果对于所有的旅馆i来说,没有其他任何一个旅馆的pxdx值同时小于pidi。那么旅馆i可以算作一个是“目的旅馆”。


题解:

这个题和蓝书P228相似,但是好难用画图法转化,转化了半天也没转化对。

这里的解法是将二维转化为一维,定义数组a[p]=d 表示所有价格为p的旅馆中最小d。然后根据a数组转化为RMQ,初始化数组。

线性扫描一遍所有旅馆,每次从(1p-1)找最小的d = d_min,如果当前旅馆的d满足 d<=d_min,则可以认为当前旅馆为目标旅馆(反过来就存在旅馆p和d同时小于当前旅馆了。所以不是目的旅馆)。

 

include<bits/stdc++.h>

using namespace std;

const int maxn = 10011;
int a[maxn];
int dmin[maxn][20];

void initmin(int n,int d[])
{
    for(int i=0;i<=n;i++)dmin[i][0]=d[i];
    for(int j=1;(1<<j)<=n;j++)
        for(int i=1;i+(1<<j)-1<=n;i++)
            dmin[i][j] = min(dmin[i][j-1],dmin[i+(1<<(j-1))][j-1]);
}

int getmin(int l,int r)
{
    int k=0;
    while(1<<(k+1)<=r-l+1)k++;
    return min(dmin[l][k],dmin[r-(1<<k)+1][k]);
}

struct node
{
    int p,d;
    bool operator <(const node& a)const
    {
        if(p==a.p)
            return d<a.d;
        return p<a.p;
    }
}ns1[maxn],ns2[maxn];

int main()
{
    int n;
    while(cin>>n)
    {
        fill(a,a+maxn,0x3f3f3f3f);
        for(int i=1;i<=n;i++)
        {
            int p,d;
            scanf("%d%d",&p,&d);
            p++,d++;
            ns1[i].p=p;
            ns1[i].d=d;
            a[p]=min(a[p],d);
        }

        initmin(maxn,a);
        int cnt=0;
        for(int i=1;i<=n;i++)
        {
            int p,d;
            p = ns1[i].p;
            d = ns1[i].d;
            if(p==1)
            {
                ns2[++cnt]=ns1[i];
            }
            else
            {
                int d_min = getmin(1,p-1);
                if(d<=d_min)///不能dmin比d小了。
                    ns2[++cnt]=ns1[i];
            }
        }

        sort(ns2+1,ns2+1+cnt);
        cout<<cnt<<endl;
        for(int i=1;i<=cnt;i++)
            printf("%d %d\n",ns2[i].p-1,ns2[i].d-1);
    }


}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值