Problem A. Ascending Rating

Problem A. Ascending Rating

题目:

Problem A. Ascending Rating

题意:

   给定一个序列a[1..n],对于每个长度为m 的连续子区间,求出区间a 的最大值以及从左往右扫描该区间时a 的最大值的变化次数。

思路:

   按照r 从m 到n 的顺序很难解决这个问题,考虑按照r 从n 到m 的顺序倒着求出每个区间的答案。按照滑窗最大值的经典方法维护a 的单调队列,那么队列中的元素个数就是最大值的变化次数。时间复杂度O(n)

代码:

#include<cstdio>
#include<algorithm>
using namespace std;

typedef long long LL;
const LL inf=1e16;
const int maxn = 1e7+1e6;
struct node
{
    LL num,nb;
} que[maxn];
LL a[maxn];
LL n,m,k,p,q,r,mod;

void getMax()
{
    ///单调递减队列
    que[0].nb=0;
    que[0].num=inf;

    int L=0,R=0;
    for(int i=1;i<m;i++){
        int id = n-i+1;     ///逆序
        while(a[id]>=que[R].num&&L<=R)--R;
        que[++R].num=a[id];
        que[R].nb=i;
    }
    LL A = 0, B = 0;
    int left = n-m+1;
    for(int i=m;i<=n;i++){
        int id = n-i+1;   ///逆序
        while(a[id]>=que[R].num&&L<=R)--R;
        que[++R].num=a[id];
        que[R].nb=i;
        while(que[L].nb<=i-m)++L;
        A += (que[L].num^left);
        B += (R-L+1)^left;
       // printf("%lld %lld
",que[L].num,(LL)(R-L+1));
        left--;

    }
    printf("%lld %lld
",A, B);

}

int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {

        scanf("%lld%lld%lld%lld%lld%lld%lld",&n,&m,&k,&p,&q,&r,&mod);
        for(int i=1; i<=k; i++)scanf("%lld",&a[i]);
        for(int i=k+1; i<=n; i++)
        {
            a[i]=(p*a[i-1]+q*i+r)%mod;
        }
        getMax();
    }
    return 0;
}
原文地址:https://www.cnblogs.com/longl/p/9395610.html