zoukankan      html  css  js  c++  java
  • [Noip2011] 选择客栈

    Description

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

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

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

    Input

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

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

    Output

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

    Hint

    对于 (30\%) 的数据,有 (nleq 100)

    对于 (50\%) 的数据,有 (nleq 1,000)

    对于 (100\%) 的数据,有 (2 leq nleq 200,000)(0<k leq 50)(0leq pleq 100) , $0leq $最低消费 (leq 100)

    Solution

    我竟然做了一个小时我好菜啊


    构思部分

    观察到如果区间 ([l,r]) 可行的话,那么一定存在 $iin [l,r] $ 使得 (val[i]leq p)

    也就是说,对于这个区间的右端点 (r),如果知道了它左边有一个 (i) 满足 (val[i]leq p),那么这个 (i) 左边的点都可以对答案有贡献。

    稍微贪心的想,我们想找的这个 (i) 一定是离 (r) 最近的点,否则,一定可以找到离 (r) 更近且满足要求的点,使得答案不会变差。

    那么问题就转化为了对于每一个点 (p),找出它左边第一个满足 (val[i]leq p) 的点 (i),然后所有与 (p) 颜色相同并且在 (i) 左边的点都会与 (p) 对答案产生 (1) 的贡献。


    实现部分

    所以,我们只需要对每个颜色开一个数组 (col[i][j]=k) 表示所有颜色为 (i) 的点中从左向右第 (j) 个是点 (k)

    另外,每个点记录它左边且最接近它的一个点 (i) 使得 (val[i]leq p) 记为 (last) 数组(注意这里 (last[i]) 是可以等于 (i) 的)。

    然后枚举每个点 (i),首先在 (col[idx[i]]) 中二分出相同颜色这个点前面有 (b) 个点,同时根据 (last[i]) 二分出相同颜色在 (last[i]) 前面有 (c) 个点。

    注意,这时候要分情况讨论了:

    1. 如果 (i=last[i]) ,也就是说无论左端点在哪,这两个人都可以去右端点吃饭,所以直接 (ans+=b) 即可。
    2. (i!=last[i]) 但是 (idx[i]=idx[last[i]]),也就是说,这个点前面满足要求的最近的点跟它颜色一样。注意到我们的 (c)(last[i]) 前面(c) 个点,如果颜色相同的话,应该算上 (last[i]) ,所以 (ans+=c+1)
    3. 最后一种情况,即 (i!=last[i];and;idx[i]!=idx[last[i]]) ,这种情况是最简单的, (ans+=c) 就OK了。

    时间复杂度 (mathcal{O(nlogn)})

    Code

    #include<cstdio>
    #include<algorithm>
    #define N 200005
    #define ll long long
    #define min(A,B) ((A)<(B)?(A):(B))
    
    ll ans;
    int n,k,p;
    int qzh[N];
    int val[N];
    int idx[N];
    int last[N];
    int col[55][N];
    
    signed main(){
        scanf("%d%d%d",&n,&k,&p);
        qzh[0]=p+1;
        for(int i=1;i<=n;i++){
            int a;
            scanf("%d%d",&a,&val[i]);
            idx[i]=a;
            col[a][++col[a][0]]=i;
            qzh[i]=min(qzh[i-1],val[i]);
            last[i]=(val[i]<=p?i:last[i-1]);
            //printf("i=%d,qzh=%d,last=%d
    ",i,qzh[i],last[i]);   
        }
        for(int i=1;i<=n;i++){
            if(qzh[i]>p) continue;
            int b=std::lower_bound(col[idx[i]]+1,col[idx[i]]+1+col[idx[i]][0],i)-col[idx[i]];
            int c=std::lower_bound(col[idx[i]]+1,col[idx[i]]+1+col[idx[i]][0],last[i])-col[idx[i]]-1;
            if(last[i]==i) ans+=(ll)b-1;
            else if(idx[last[i]]!=idx[i]) ans+=(ll)c;
            else ans+=(ll)c+1;
            //printf("i=%d,b=%d,c=%d,ans=%lld
    ",i,b,c,ans);
        }
        printf("%lld
    ",ans);
        return 0;
    }
    
  • 相关阅读:
    OpenFire源码学习之十九:在openfire中使用redis插件(上)
    OpenFire源码学习之十八:IOS离线推送
    OpenFire源码学习之十七:HTTP Service插件
    OpenFire源码学习之十六:wildfire
    OpenFire源码学习之十五:插件开发
    OpenFire源码学习之十四:插件管理
    OpenFire源码学习之十三:消息处理
    数据挖掘入门
    iOS小技巧
    图片加载完成之前对图片高度侦测
  • 原文地址:https://www.cnblogs.com/YoungNeal/p/9080195.html
Copyright © 2011-2022 走看看