问题描述:
给定一个序列 a[1..n],对于每个长度为 m 的连续子区间,求出区间 a 的最大值以及从左往右扫描该区间时 a 的最大值的
变化次数。1 ≤ m ≤ n ≤ 107。
按照 r 从 m 到 n 的顺序很难解决这个问题。
考虑按照 r 从 n 到 m 的顺序倒着求出每个区间的答案。
按照滑窗最大值的经典方法维护 a 的单调队列,那么队列
中的元素个数就是最大值的变化次数。
时间复杂度 O(n)。
#include"bits/stdc++.h"
using namespace std;
typedef long long ll;
ll n,m,k,p,q,r,mod;
ll a[10000007];
ll qp[20000007];
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]=(a[i-1]*p+q*i+r)%mod;
}
int top=0,bot=1;
ll sa=0,sb=0;
for(ll i=n;i>=1;i--){
while(top>=bot&&a[i]>=a[qp[top]]) top--;
qp[++top]=i;
int ed=i+m-1;
if(i<=n-m+1){
while(qp[bot]>ed) bot++;
sa+=(a[qp[bot]]^i);
sb+=(i^(top-bot+1));
}
}
printf("%lld %lld\n",sa,sb);
}
return 0;
}