2018 Multi-University Training Contest 3
6319.Problem A. Ascending Rating
题意就是给你长度为k的数列,如果数列长度k<n,就利用一个构造数列的方法构造数列使数列长度为n。
然后求定长区间为m的数列中最大值是几,最大值是第几次更新maxnum得到的,得到所有结果之后,用一个求和的公式将结果输出来,具体题意自己翻译。
滑窗问题,单调队列可以解决。关于滑窗问题和单调队列,具体的自行百度。
对于这个题,倒着遍历数列才能既找到最大值,又能找到COUNT,如果正着遍历,只能找到最大值,但是没法用tail-head得到COUNT,可能标记进来过的数的下标然后区间求和应该也可以得到,但是超不超时就不知道了。。。
官方题解:
按照r从m到n的顺序很难解决这个问题。
考虑按照r从n到m的顺序倒着求出每个区间的答案。按照滑窗最大值的经典方法维护a的单调队列,那么队列中的元素个数就是最大值的变化次数。
时间复杂度O(n)。
其他的应该没什么了。
代码:
1 //1001-经典滑窗问题-单调队列 2 #include<iostream> 3 #include<cstdio> 4 #include<cstring> 5 #include<cstdlib> 6 #include<queue> 7 #include<algorithm> 8 #include<cassert> 9 #include<queue> 10 #include<set> 11 using namespace std; 12 typedef long long ll; 13 const int maxn=1e7+10; 14 15 int arr[maxn],maxval[maxn],que[maxn],num[maxn]; 16 int n,m,k,p,q,r,mod; 17 18 void getAns(int n,int m) 19 { 20 int head=0,tail=0; 21 for(int i=n;i>=1;i--){ 22 while(tail>head&&arr[que[tail-1]]<=arr[i]) tail--; 23 que[tail++]=i; 24 if(i>n-m+1) continue; 25 while(que[head]>i+m-1) head++;//队头距离当前区间太远,head++变大,才满足区间长度,因为head越大,就越接近tail,因为是倒着的 26 maxval[i]=arr[que[head]]; 27 num[i]=tail-head;//对每个区间的count为队尾-队头的值 28 } 29 } 30 31 int main() 32 { 33 int t; 34 scanf("%d",&t); 35 while(t--){ 36 scanf("%d%d%d%d%d%d%d",&n,&m,&k,&p,&q,&r,&mod); 37 for(int i=1;i<=k;i++) 38 scanf("%d",&arr[i]); 39 for(int i=k+1;i<=n;i++) 40 arr[i]=((ll)p*arr[i-1]%mod+(ll)q*i%mod+r)%mod; 41 getAns(n,m); 42 ll a=0,b=0; 43 for(int i=1;i<=n-m+1;i++){ 44 a+=maxval[i]^i; 45 b+=num[i]^i; 46 } 47 printf("%lld %lld ",a,b); 48 } 49 }
mdzz,求数列的时候,取模写错了,wa了好几次。