2018 Multi-University Training Contest 3 Problem A. Ascending Rating (单调队列)

Problem A. Ascending Rating

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 524288/524288 K (Java/Others)
Total Submission(s): 3142    Accepted Submission(s): 1020


 

Problem Description

Before the start of contest, there are n ICPC contestants waiting in a long queue. They are labeled by 1 to n from left to right. It can be easily found that the i-th contestant's QodeForces rating is ai.
Little Q, the coach of Quailty Normal University, is bored to just watch them waiting in the queue. He starts to compare the rating of the contestants. He will pick a continous interval with length m, say [l,l+m−1], and then inspect each contestant from left to right. Initially, he will write down two numbers maxrating=−1and count=0. Everytime he meets a contestant k with strictly higher rating than maxrating, he will change maxrating to ak and count to count+1.
Little T is also a coach waiting for the contest. He knows Little Q is not good at counting, so he is wondering what are the correct final value of maxrating and count. Please write a program to figure out the answer.

 

Input

The first line of the input contains an integer T(1≤T≤2000), denoting the number of test cases.
In each test case, there are 7 integers n,m,k,p,q,r,MOD(1≤m,k≤n≤107,5≤p,q,r,MOD≤109) in the first line, denoting the number of contestants, the length of interval, and the parameters k,p,q,r,MOD.
In the next line, there are k integers a1,a2,...,ak(0≤ai≤109), denoting the rating of the first k contestants.
To reduce the large input, we will use the following generator. The numbers p,q,r and MOD are given initially. The values ai(k<i≤n) are then produced as follows :

ai=(p×ai−1+q×i+r)modMOD


It is guaranteed that ∑n≤7×107 and ∑k≤2×106.

 

Output

Since the output file may be very large, let's denote maxratingi and counti as the result of interval [i,i+m−1].
For each test case, you need to print a single line containing two integers A and B, where :


Note that ``⊕'' denotes binary XOR operation.

 

Sample Input

1

10 6 10 5 5 5 5

3 2 2 1 5 7 6 8 2 9

Sample Output

46 11

Source

2018 Multi-University Training Contest 3

题目大意:

官方解释:给定一个序列 a[1..n],对于每个长度为 m 的连续子区间, 求出区间 a 的最大值以及从左往右扫描该区间时 a 的最大值的变化次数。输入n,m,k,p,q,r,mod,接下来输入k个数,在k个数之后数组的值为ai=(p×ai−1+q×i+r)modMOD,然后让你计算

  其中maxrating表示在[i,i+m−1]区间的最大值,count表示在[i,i+m−1]区间内最大值变化的次数

注意每个区间中maxrating初始化为-1 count初始化为0,也就是说没次移动更新的时候,maxrating和count都要重新算.

样例:输入的数为:3 2 2 1 5 7 6 8 2 9 先设A=0 B=0

对A:一开始i为1,即对区间为[1,6]取最大值 即7,A+=7^i=7^1  ,接下来i加到2,即对区间为[2,7]取最大值还是7,A+=7^i=7^2 以此类推,当i一直加到10-6+1=5时,即对区间为[5,10]取最大值即9,A+=9^i=9^5 ,最后就得出A了

同理对B:一开始i为1,即对区间为[1,6]取最大值变化的次数即3,B+=3^i=3^1  ,接下来i加到2,即对区间为[2,7]取最大值变化的次数还是3,B+=3^i=3^2 以此类推,当i一直加到10-6+1=5时,即对区间为[5,10]取最大值变化次数 即4,B+=4^i=4^5 ,最后就得出B了。

解题思路:

如果按照上面这样暴力取的话,肯定会TLE,这时我们就要用

到单调队列,单调队列在这个区间内的数都是以小到大的,即队尾是最小的,队头为最大的,当要放进一个数的时候,如果队列中的数比放进的数小的话就pop出,这样就能保持队头是最大,当我们遍历从n往前开始放的时候,就相当于我们从前面比较大的数(相当于遇到大的数就放进去),那么比较的次数就是队列的大小(当队头元素不在区间的时候,就将其抛出

emmm看代码比较好理解

代码:

#include<bits/stdc++.h>
using namespace std;
#define  LL long long
#define MAXN (LL)(1e+7)+10
struct queu { //队列存的是数组的下标 
    LL front;
    LL rear;
    LL a[MAXN]; 
} que;
LL b[MAXN];
void push(LL num) { //将下边推进队列 
    while(que.rear!=que.front && b[num]>=b[que.a[que.rear-1]] ) {   
        que.rear--; 	//为维护单调队列,当新加元素的值比队中的值大的时候,将队中比该值小的全部pop()
    }
    que.a[que.rear]=num;
    que.rear++;
}
void clean() { // 初始化 
    que.front=1;
    que.rear=1;
}
LL getsize() { //获取队列的大小 
    return que.rear-que.front;
}
LL getmax() { //获取最大值,队头元素即为最大值 
    return b[que.a[que.front]];
}
int main() {
    LL t;
    scanf("%lld",&t);
    LL n,m,k,p,q,r,mod;
    while(t--) {
        scanf("%lld %lld %lld %lld %lld %lld %lld",&n,&m,&k,&p,&q,&r,&mod);
        LL num;
        clean();
        for(LL i=1; i<=n; i++) { //这有好大的坑,被这卡输入疯狂TLE,题目说的是在k之后就不用输入了,直接套公式 
            if(i>k) {
                b[i]=((p*b[i-1])+(q*i)+r)%mod; //自己比较菜,今天才发现mod运算原来占用很多时间,在mod这块也TLE了好久 
            } else {
            	scanf("%lld",&num);
                b[i]=num;
            }
        }
        LL A=0,B=0;
        LL s=n-m+1;
        for(LL i=n; i>n-m; i--) { //倒着取,这样就能保证队列的大小就是max变化的次数 
            push(i); //先对第一个区间进行进队 
        }
        A+=getmax()^(s);
        B+=getsize()^(s);
        LL test=0;
        LL index =n-m;
        while(index>=1) { //在这之后每一次移动都要判断区间移动会不会影响队头的值 
            if(que.a[que.front] == n-test) {  //如果队头的值和不再区间内,则将其抛出相当于pop() 
                que.front++;
            }
            push(index);
            index--;
            test++;
            A+=getmax()^(s-test);
            B+=getsize()^(s-test);

        }
        printf("%lld %lld\n",A,B);
    }
    return 0;
}
发布了13 篇原创文章 · 获赞 4 · 访问量 4199

猜你喜欢

转载自blog.csdn.net/yiyiLy/article/details/81303906
今日推荐