「一本通 4.2 练习 3」选择客栈 (loj2597)(noip2011)

思路:

  这道题简单来说就是,选出两个旅店的色调相同且中间(包括两边)存在价格小于p的旅店的个数。

  于是很容易想到,在读入时进行预处理将每一种色调的酒店归为一类。

  然而如何去判断两个酒店中间有没有价格小于p的酒店呢?

  其实只需要定义一个前缀和sum[i]表示从1到i之间的价格小于等于p的酒店个数,那么i和j位置的两个酒店之间符合要求的咖啡馆个数为sum[j] - sum[i-1],只要它不为0,就是符合条件的。

  但是,每一个色调的数组大小不好开,在这里我用的是STL的vector(在这道题里vector并不算慢,进行200万次push_back操作只用了100+ms)

  在枚举时只要发现了一对i, j 那么j之后的所有酒店均可以与i结合凑成一堆,于是整体加上,直接break

  最后输出累加结果即可。时间复杂度约为400 × k

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#include<vector>
using namespace std;
const int maxk = 10010;
const int maxn = 2000010;
inline void qread(int &x){
    x = 0;
    register int ch = getchar(), flag = 0;
    while(ch < '0' || ch > '9')    {
        if(ch == '-')    flag = 1;
        ch =getchar();
    }
    while(ch >='0' && ch <='9'){
        x = 10 * x + ch - 48;
        ch = getchar();
    }
    if(flag)    x = -x;
}
int n, k, p, cl, co;
long long ans;
vector<int> v[maxk];
int sum[maxn];
int main(void)
{
    qread(n);
    qread(k);
    qread(p);
    for(int i=1; i<=n; ++i){
        qread(cl);
        cl++;
        qread(co);
        sum[i] = sum[i-1] + (co<=p);
        v[cl].push_back(i);
    }
    for(int i=1; i<=k; ++i){
        for(int j=0; j<v[i].size(); ++j)
            for(int t=j+1; t<v[i].size(); ++t)
                if(sum[v[i][t]] - sum[v[i][j]-1]){
                    ans += v[i].size() - t;
                    break;
                }
    }
    printf("%lld\n", ans);
}

 

  

posted @ 2018-08-14 15:30  junk_yao  阅读(186)  评论(0编辑  收藏  举报