单调队列模板链接
https://blog.csdn.net/qq_41268947/article/details/81483268
Problem A. Ascending Rating
Problem Description
Before the start of contest, there are ICPC contestants waiting in a long queue. They are labeled by to from left to right. It can be easily found that the -th contestant’s QodeForces rating is .
Little Q, the coach of Quailty Normal University, is bored to just watch them waiting in the queue. He starts to compare the rating of the contestants. He will pick a continous interval with length , say , and then inspect each contestant from left to right. Initially, he will write down two numbers and . Everytime he meets a contestant with strictly higher rating than , he will change to and to .
Little T is also a coach waiting for the contest. He knows Little Q is not good at counting, so he is wondering what are the correct final value of and . Please write a program to figure out the answer.
Input
The first line of the input contains an integer , denoting the number of test cases. In each test case, there are integers in the first line, denoting the number of contestants, the length of interval, and the parameters . In the next line, there are integers , denoting the rating of the first contestants. To reduce the large input, we will use the following generator. The numbers and are given initially. The values are then produced as follows :
Output
Since the output file may be very large, let’s denote and as the result of interval . For each test case, you need to print a single line containing two integers and , where :
Sample Input
1
10 6 10 5 5 5 5
3 2 2 1 5 7 6 8 2 9
Sample Output
46 11
题意
有序列a1~an,对于每个连续的长为m的子区间[ax,ax+m-1],求两个值:maxrating和count,两者初始值均为0,从左到右扫描每个元素,如果有元素大于maxrating,则更新maxrating且让count++。求出每个区间的maxrating和count后,再按题给公式求出A和B。
思路
这道题运用单调队列,但是我们不能从首到尾判断,因为单调队列只能存每个区间的最大值,但count求的是最大值更新了多少次,那么,区间变换了,count值也会不同。还有就是如果遇到那种最小值不在该区域内,需要队首后移这时也需要重算count
所以倒过来,从尾到首进行单调队列
代码
#include<cstdio>
const int N=10000010;
int i,a[N],v[N],h,t; //v是单调队列,h是队首,t是队尾
long long A,B;
int main()
{
int T,n,m,k,p,q,r,mod;
scanf("%d",&T);
while(T--)
{
scanf("%d%d%d%d%d%d%d",&n,&m,&k,&p,&q,&r,&mod);
for(i=1;i<=k;i++)
scanf("%d",&a[i]);
for(i=k+1;i<=n;i++)
a[i]=(1LL*p*a[i-1]+1LL*q*i+r)%mod;
A=0,B=0;
h=1,t=0;
for(i=n;i;i--)
{
while(h<=t&&a[v[t]]<=a[i]) t--;
//队列递减所以队尾上小于要插入值的元素都删除
v[++t]=i;
if(i+m-1<=n)//i可以作为区间起点了
{
while(v[h]>=i+m) h++;//去掉区间外的元素
A+=i^a[v[h]];
B+=i^(t-h+1);
}
}
printf("%lld %lld\n",A,B);
}
return 0;
}