【枚举优化】【NOIP2011提高组】选择客栈 hotel

选择客栈

(hotel.pas/c/cpp)

【问题描述】

  丽江河边有 n 家很有特色的客栈,客栈按照其位置顺序从1 到n 编号。每家客栈都按照某一种色调进行装饰(总共k 种,用整数0 ~ k-1 表示),且每家客栈都设有一家咖啡店,每家咖啡店均有各自的最低消费。

  两位游客一起去丽江旅游,他们喜欢相同的色调,又想尝试两个不同的客栈,因此决定分别住在色调相同的两家客栈中。晚上,他们打算选择一家咖啡店喝咖啡,要求咖啡店位于两人住的两家客栈之间(包括他们住的客栈),且咖啡店的最低消费不超过p。

  他们想知道总共有多少种选择住宿的方案,保证晚上可以找到一家最低消费不超过p元的咖啡店小聚。

【输入】

  输入文件hotel.in,共n+1行

  第一行三个整数 n,k,p,每两个整数之间用一个空格隔开,分别表示客栈的个数,色
调的数目和能接受的最低消费的最高值;

  接下来的 n 行,第i+1 行两个整数,之间用一个空格隔开,分别表示i 号客栈的装饰色
调和i 号客栈的咖啡店的最低消费。

【输出】

  输出文件名为 hotel.out

  输出只有一行,一个整数,表示可选的住宿方案总数

【输入输出样例】

hotel.in

5 2 3

0 5

1 3

0 2

1 4

1 5

 

hotel.out

3

 

【输入输出样例说明】
客栈编号 ① ② ③ ④ ⑤
色调 0 1 0 1 1
最低消费 5 3 2 4 5
2 人要住同样色调的客栈,所有可选的住宿方案包括:住客栈①③,②④,②⑤,④⑤,但是若选择住4、5 号客栈的话,4、5 号客栈之间的咖啡店的最低消费是4,而两人能承受的最低消费是3 元,所以不满足要求。因此只有前3 种方案可选。

【数据范围】
对于 30%的数据,有n≤100;
对于 50%的数据,有n≤1,000;
对于 100%的数据,有2≤n≤200,000,0

 

 

前面已经发过一次pascal的了http://www.cnblogs.com/oijzh/archive/2012/08/20/2647058.html 

乍一看这一题,想到的第一算法就是枚举,也能得很高的分,要AC重点就在优化

 

我们可以维护出一个pre[]数组来储存当前节点的前一个颜色相同的节点的下标(注意是前一个,后面方便)

再维护一个数组pp[]表示前 i 个中满足最低消费的个数(后面判断i~j中是否满足只需要 p[i]-p[j-1]>0 即可,可以少很多枚举)

再用一个数组num[]表示在闭区间[1,i]中与当前 i 颜色相同的点的个数

现在这三个数组就可以配合起来进行优化了

如果我们找到了[m,n]这个区间满足,那么[pre[m],n]这个区间也必定满足(想想为什么?区间[m,n]满足就必定有一个是满足最低消费的,那么[pre[m],n]又包含[m,n],自然而然也就满足最低消费的要求),同理[pre[pre[m]],n]也会满足。。。那么我们只需要找到一个区间[m,n]满足,就不必再找以 n 结尾的区间,直接把答案 sum 中加上num[m]即可

这个懂了,程序自然而然也就出来了

C++ Code

/*
C++ Code
http://oijzh.cnblogs.com
*/
#include
#define MAXN 200010

int n,colors,minp,c[MAXN],p[MAXN],num[MAXN],pre[MAXN],pp[MAXN],sum=0;

int main()
{
    freopen("hotel.in","r",stdin);
    freopen("hotel.out","w",stdout);
    scanf("%d%d%d",&n,&colors,&minp);
    int i,j;
    for(i=1;i<=n;i++)
    {
        scanf("%d%d",&c[i],&p[i]);
        pp[i]=pp[i-1];
        if(p[i]<=minp)pp[i]++;//区间[1,i]中满足最低消费的个数
    }
    for(i=2;i<=n;i++)
        for(j=i-1;j>0;j--)
            if(c[i]==c[j])
                { pre[i]=j;break; }//处理前驱
    for(i=1;i<=n;i++)
        num[i]=num[pre[i]]+1;//区间[1,i]中颜色与当前i相同的个数
    for(i=1;i<=n;i++)
    {
        j=pre[i];
        while(j!=0)
        {
            if(pp[i]-pp[j-1]>0)
            {
                sum+=num[j];
                //printf("i=%d j=%d sum=%d\n",i,j,sum);
                break;
            }
            j=pre[j];
        }
    }
    printf("%d",sum);
    return 0;
}

 

  

 下面是评测结果,C++秒过 

【枚举优化】【NOIP2011提高组】选择客栈 hotel_第1张图片

转载于:https://www.cnblogs.com/oijzh/archive/2012/09/05/2672479.html

你可能感兴趣的:(c/c++)