2018多校赛第三场 Ascending Rating(单调队列)

题意

给定数组a[1..k],然后给出一个求a[k+1..n]的递推公式。m表示一个区间长度。现要求出所有区间长度为m的区间的maxrating和count。maxrating表示这个区间的最大值,count表示这个区间的上升序列长度。

解题

维护所有固定长度区间的最大值,显然是单调队列的经典应用。
而count可以在O(n)维护maxrating值时同时维护。
从后往前进行遍历数组元素,维护一个单调递减的队列,这个队列的长度就是count值。

AC代码

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

const int maxn=1e7+7;
typedef long long ll;
int a[maxn];
int maxr[maxn],cnt[maxn];
int n,m,k,p,q,r,mod;
//maxr[i]表示第i~i+m-1的最大值
//cnt[i]表示第i~i+m-1最大值变化的次数

//单调队列
int que[maxn],head,tail;
void solve()
{
    head=1,tail=0;
    for(int i=n;i>=1;i--)
    {
        while(head<=tail && a[i]>=a[que[tail]]) tail--;
        que[++tail]=i;
        if(i>n-m+1) continue;
        while(head<=tail && que[head]>=i+m) head++;
        maxr[i]=a[que[head]];
        cnt[i]=tail-head+1;
    }
}
int main()
{
    int T;
    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]=((ll)a[i-1]*p+(ll)q*i+r)%mod;
        solve();
        ll A=0,B=0;
        for(int i=1;i<=n-m+1;i++)
        {
            A+=maxr[i]^(i);
            B+=cnt[i]^(i);
        }
        printf("%lld %lld\n",A,B);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_37685156/article/details/81298603