题意:
给定一个序列a[1…n],对于每个长度为m的连续子区间,求出区间a的最大值以及从左往右扫描该区间时a的最大值的变化次数。
分析:
按照r从m到n的顺序很难解决这个问题。
考虑按照r从n到m的顺序倒着求出每个区间的答案。
按照滑动窗口最大值的经典方法维护a的单调队列,那么队列中的元素个数就是最大值的变化次数。
#include<stdio.h>
#include<queue>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<string>
using namespace std;
typedef long long int ll;
const int N=1e7+7;
int a[N],Q[N],n,m;
ll A,B;
int k,t,q,p,r,MOD;
void get_mx()
{
int head,tail;
head=tail=0;
for(int i=n;i>=1;i--)
{
while((head<tail)&&(a[Q[tail-1]]<=a[i]))tail--;
Q[tail++]=i;
if(i<=n-m+1)
{
while((head<tail)&&(Q[head]>=i+m))head++;
// printf("%d\n",tail-head+1);
A+=i^a[Q[head]];
B+=i^(tail-head);
}
}
}
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]);
A=0;
B=0;
for(int i=k+1;i<=n;i++)a[i]=(1LL*p*a[i-1]%MOD+1LL*q*i%MOD+r%MOD)%MOD;
get_mx();
printf("%lld %lld\n",A,B);
}
return 0;
}