CFGym 101505I 题解

一、题目链接

  http://codeforces.com/gym/101505

二、题意

  这题其实主要就是题意,理解题意后,就是水题了。我想了下,主要原因就是这几点:

  1、题意太过英文化,很多句子不能和中文一对一翻译,导致理解出现偏差。

  2、题意没讲清楚。对于每个测试样例,第一个数据是不用考虑的。这点题目没说,要是说了,估计这题过的人更多。

  主要意思就是:给你N组数组,每组一个t和一个v,其实输入的t是递增的(严不严格无所谓)。再给M个询问,询问格式是:<大于或小于> <聚集函数> <时间>。比如:gt max 300,表示:对于第i(1<=i<=N)个数据,若它的时间是Ti,判断它的值Vi是否比[Ti - 300, Ti)这个区间内记录的数据的V的最大值还大。如果是,结果+1,然后输出有多少组这样的数据。对于每个询问都是如此。注意,第一组数据是不用考虑的。因为它前面没有数据。

三、思路

  理解题意后,思路就很简单了。对于每个询问,循环遍历所有数据(从第2个开始),假设询问时间为t, 第i组数据的时间为Ti,找到大于等于Ti-t的时间所在下标j(可以通过二分找到,因为数据位置不会变,所以时间和值可以分开存,而不需要结构体。如果用结构体,就要手写lower_bound函数了),计算区间[j, i - 1)内的最大值、最小值或平均值。一维区间求最值,可以用线段树。

四、源代码

#include<bits/stdc++.h>
using namespace std;
typedef pair<int, int> PII;
const int maxn = 100010;
int n, m;
int tim[maxn], val[maxn], sum[maxn];
const PII INF = make_pair(1 << 30, 0);
PII data[maxn << 1];

void update(int x, int v) {
    int _t = x + m - 1;
    data[_t].first = data[_t].second = v;
    for(_t >>= 1; _t > 0; _t >>= 1) {
        data[_t].first = min(data[_t << 1].first, data[_t << 1 | 1].first);
        data[_t].second = max(data[_t << 1].second, data[_t << 1 | 1].second);
    }
}

void init() {
    int _t = 1;
    while(_t < n)_t <<= 1;
    m = _t;
    for(int i = 0; i < m << 1; ++i)data[i] = INF;
    for(int i = 1; i <= n; ++i)update(i, val[i]);
}

PII query(int x, int y, int root = 1, int l = 1, int r = m) {
    if(y < l || x > r)return INF;
    else if(l >= x && r <= y)return data[root];
    else {
        int mid = (l + r) >> 1;
        PII left = query(x, y, root << 1, l, mid);
        PII right = query(x, y, root << 1 | 1, mid + 1, r);
        return make_pair(min(left.first, right.first), max(left.second, right.second));
    }
}

int Max(int idx, int before, int type) {
    int j = lower_bound(tim + 1, tim + n + 1, tim[idx] - before) - tim;
    if(j == idx)return type == 0 ? 1 << 30 : 0;
    PII ans = query(j, idx - 1);
    return ans.second;
}

int Min(int idx, int before, int type) {
    int j = lower_bound(tim + 1, tim + n + 1, tim[idx] - before) - tim;
    if(j == idx)return type == 0 ? 1 << 30 : 0;
    PII ans = query(j, idx - 1);
    return ans.first;
}

double Avg(int idx, int before) {
    int j = lower_bound(tim + 1, tim + n + 1, tim[idx] - before) - tim;
    return (sum[idx - 1] - sum[j - 1]) / (1.0 * (idx - j));
}

int main() {
    char op1[5], op2[5];
    while(~scanf("%d", &n)) {
        memset(sum, 0, sizeof(sum));
        memset(op1, '\0', sizeof(op1));
        memset(op2, '\0', sizeof(op2));
        for(int i = 1; i <= n; ++i)scanf("%d%d", &tim[i], &val[i]);
        for(int i = 1; i <= n; ++i)sum[i] = sum[i - 1] + val[i];
        init();
        int q, before;
        scanf("%d", &q);
        while(q--) {
            scanf("%s%s%d", op1, op2, &before);
            int cnt = 0;
            if(strcmp(op1, "gt") == 0) {
                if(strcmp(op2, "max") == 0) {
                    for(int i = 2; i <= n; ++i)if(val[i] > Max(i, before, 0))++cnt;
                } else if(strcmp(op2, "avg") == 0) {
                    for(int i = 2; i <= n; ++i) if((double)val[i] > Avg(i, before))++cnt;
                } else if(strcmp(op2, "min") == 0) {
                    for(int i = 2; i <= n; ++i)if(val[i] > Min(i, before, 0))++cnt;
                }
            } else if(strcmp(op1, "lt") == 0) {
                if(strcmp(op2, "max") == 0) {
                    for(int i = 2; i <= n; ++i)if(val[i] < Max(i, before, 1))++cnt;
                } else if(strcmp(op2, "avg") == 0) {
                    for(int i = 2; i <= n; ++i)if((double)val[i] < Avg(i, before))++cnt;
                } else if(strcmp(op2, "min") == 0) {
                    for(int i = 2; i <= n; ++i)if(val[i] < Min(i, before, 1))++cnt;
                }
            }
            printf("%d\n", cnt);
        }
    }
}

/*
5
4 16
9 49
46 93
55 16
62 55
8
gt max 29
lt avg 15
gt min 34
gt max 4
lt min 44
lt max 29
gt max 42
lt avg 10

10
60 30
120 28
180 35
240 34
300 40
360 31
420 28
480 2
540 42
600 30
2
gt avg 7200
lt min 300


8
1 10
5 30
10 50
15 45
20 55
25 40
30 30
35 20
6
gt max 10
gt avg 10
gt min 10
lt max 10
lt avg 10
lt min 10


*/

变量m是为设计线段树而定义的,因为n不会刚好是2的幂。

转载于:https://www.cnblogs.com/fuzhihong0917/p/7622443.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值