Problem A. Ascending Rating
题目:
Problem A. Ascending Rating
题意:
给定一个序列a[1..n],对于每个长度为m 的连续子区间,求出区间a 的最大值以及从左往右扫描该区间时a 的最大值的变化次数。
思路:
按照r 从m 到n 的顺序很难解决这个问题,考虑按照r 从n 到m 的顺序倒着求出每个区间的答案。按照滑窗最大值的经典方法维护a 的单调队列,那么队列中的元素个数就是最大值的变化次数。时间复杂度O(n)
代码:
#include<cstdio> #include<algorithm> using namespace std; typedef long long LL; const LL inf=1e16; const int maxn = 1e7+1e6; struct node { LL num,nb; } que[maxn]; LL a[maxn]; LL n,m,k,p,q,r,mod; void getMax() { ///单调递减队列 que[0].nb=0; que[0].num=inf; int L=0,R=0; for(int i=1;i<m;i++){ int id = n-i+1; ///逆序 while(a[id]>=que[R].num&&L<=R)--R; que[++R].num=a[id]; que[R].nb=i; } LL A = 0, B = 0; int left = n-m+1; for(int i=m;i<=n;i++){ int id = n-i+1; ///逆序 while(a[id]>=que[R].num&&L<=R)--R; que[++R].num=a[id]; que[R].nb=i; while(que[L].nb<=i-m)++L; A += (que[L].num^left); B += (R-L+1)^left; // printf("%lld %lld ",que[L].num,(LL)(R-L+1)); left--; } printf("%lld %lld ",A, B); } 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]=(p*a[i-1]+q*i+r)%mod; } getMax(); } return 0; }