[Noip2011] 选择客栈

Description

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

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

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

Input

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

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

Output

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

Hint

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

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

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

Solution

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


构思部分

观察到如果区间 \([l,r]\) 可行的话,那么一定存在 $i\in [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\n",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\n",i,b,c,ans);
    }
    printf("%lld\n",ans);
    return 0;
}
posted @ 2018-05-23 22:59  YoungNeal  阅读(463)  评论(0编辑  收藏  举报