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\n",a,b);
48     }
49 }

 

mdzz,求数列的时候,取模写错了,wa了好几次。