当前位置: 代码迷 >> 综合 >> 2018多校赛第三场 Ascending Rating(单调队列)
  详细解决方案

2018多校赛第三场 Ascending Rating(单调队列)

热度:69   发布时间:2023-11-22 00:21:07.0

题意

给定数组a[1..k],然后给出一个求a[k+1..n]的递推公式。m表示一个区间长度。现要求出所有区间长度为m的区间的maxrating和count。maxrating表示这个区间的最大值,count表示这个区间的上升序列长度。

解题

维护所有固定长度区间的最大值,显然是单调队列的经典应用。
而count可以在O(n)维护maxrating值时同时维护。
从后往前进行遍历数组元素,维护一个单调递减的队列,这个队列的长度就是count值。

AC代码

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <iostream>
using namespace std;const int maxn=1e7+7;
typedef long long ll;
int a[maxn];
int maxr[maxn],cnt[maxn];
int n,m,k,p,q,r,mod;
//maxr[i]表示第i~i+m-1的最大值
//cnt[i]表示第i~i+m-1最大值变化的次数//单调队列
int que[maxn],head,tail;
void solve()
{head=1,tail=0;for(int i=n;i>=1;i--){while(head<=tail && a[i]>=a[que[tail]]) tail--;que[++tail]=i;if(i>n-m+1) continue;while(head<=tail && que[head]>=i+m) head++;maxr[i]=a[que[head]];cnt[i]=tail-head+1;}
}
int main()
{int T;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]=((ll)a[i-1]*p+(ll)q*i+r)%mod;solve();ll A=0,B=0;for(int i=1;i<=n-m+1;i++){A+=maxr[i]^(i);B+=cnt[i]^(i);}printf("%lld %lld\n",A,B);}return 0;
}
  相关解决方案