1. 程式人生 > >HDU 6319 Ascending Rating 單調佇列,(最大值變化次數)

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;
}