HDU 6319 Ascending Rating 单调队列,(最大值变化次数)

题意:长度为n的序列a.对每个m大小的区间[i,i+m-1],求出该区间的最大值,以及最大值变化的次数.
例如区间(4,2,7,5),最大值变化次数为2. n<=1e7.

n<=1e7. 标准解应该为O(n). 容易想到用单调队列维护每个区间的最大值.
发现正着做单调队列的过程中,单调队列的大小 是从右往左数 最大值的变化次数.
例如区间(4,2,7,5,1,3) 单调队列中存的为(7,5,3) 因为每次加入一个数 会把前面比它小的弹出.
那么逆着做一遍单调队列即可.

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e7+5;
int n,m,k,p,q,r,mod,T,a[N];
int deq[N],front,tail;
int main(){
    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*a[i-1]*p+1ll*q*i+r)%mod;
     	ll A=0,B=0,tail=0,front=0;
		for(int i=n;i>=1;i--){
			while(front<tail && deq[front]>i+m-1)	front++;
			while(front<tail && a[deq[tail-1]]<=a[i])	tail--;
			deq[tail++]=i;
			if(i>n-m+1)	continue;
			int mx=a[deq[front]],cnt=tail-front;
			A=A+(mx^i),B=B+(cnt^i);
		} 
        printf("%I64d %I64d\n",A,B);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/noone0/article/details/81296354