2018 Multi-University Training Contest 4 A.Ascending Rating(滑窗单调队列)

题目太长了就不贴了。

题目大意是给你前k个数,让你用题目给的公式生成后n - k个数,形成一个长度为n的数列。
之后在上面滑动一个长度为m的区间(窗口),对每个区间求两个东西:
1、区间最大值
2、第一个数后有多少个数比它大。
最后分别输出每个区间上述两个值与区间编号i之间异或后的和。

经典的滑窗问题,需要倒着维护一个递减的单调队列。
单调队列的队头就是要找的最大的元素,而要求的第二个值,则可以用尾指针 - 头指针 + 1求得。
注意,这里的头尾指针和一般队列的头尾指针不一样,头指针的确指向队头,但是尾指针指向的是最新一个加进队列里的元素。
这就是为什么要倒着来维护,因为这样才能保证尾指针指在实际的第一个元素上。

ac代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int maxn = 1e7 + 5;
int a[maxn], que[maxn];

int main() {
    int T, n, m, k, p, q, r, mod;
    scanf("%d", &T);
    while(T--) {
        scanf("%d%d%d%d%d%d%d", &n, &m, &k, &p, &q, &r, &mod);
        for(int i = 1; i <= k ; i++) {
            scanf("%d", &a[i]);
        }
        // 按题意生成数组
        for(int i = k + 1; i <= n ; i++) {
            a[i] = (1LL * p * a[i - 1] + 1LL * q * i + r) % mod;
        }

        ll ans = 0, ans2 = 0;
        ll front = 1, rear = 0;
        for(int i = n; i > 0 ; i--) {
            // 把数字的索引放到单调队列里应该在的位置
            while(front <= rear && a[i] >= a[que[rear]]) {
                rear--;
            }
            que[++rear] = i;
            if(i + m - 1 <= n) {
                // 删掉已经不在当前区间里的元素
                while(que[front] >= i + m) {
                    front++;
                }
                ans += i ^ a[que[front]];
                ans2 += i ^ rear - front + 1;
            }
        }

        printf("%lld %lld\n", ans, ans2);
    }
    return 0;
}

在滑窗问题上单调队列很优秀,从上面的代码就可以看到,新元素入队时总是会覆盖旧元素,这是因为如果一个已经在队里的元素(代表着他比新入队的元素晚出现,因为是倒着来的)小于等于新元素,根本就无需再考虑这个元素,直接删掉就可以了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值