题目链接:点击这里
解题思路:
听说反向比较好做。。。。后来想想好像确实,不过比赛的时候做的是正向,就说正向吧。
先用一个单调栈处理出big[i]表示从左到右第一个大于a[i]的位置。时间复杂度O(n)
最后就说单调队列解决问题了。考虑当a[i+1]>a[i]的时候其实直接删除队首a[i]就可以了.i+1完全继承i的状态。
那么当a[i+1]<=a[i]时,如果删除a[i]队列中还有元素,那么从a[i+1]的递增序列肯定会链接到当前队首那个元素.
所以接来下就是从i+1位置到队首第一个值的位置找那一段递增序列接到队首前面就可以了。
因为所有点都之后被删除和加入一次,所以时间复杂度是O(n)
不知道是不是常数太大了,不加读入挂的话,4800MS左右,吓死了= =
#include<bits/stdc++.h>
using namespace std;
const int mx = 1e7 + 10;
typedef long long ll;
int n,m,k,p,q,r,mod,top = 0;
int que[2*mx],head,tail,num[mx],big[mx];
ll a[mx];
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("%lld",a+i);
for(int i=k+1;i<=n;i++) a[i] = (1ll*p*a[i-1]%mod+1ll*q*i%mod+r)%mod;
head = tail = 0;
que[tail++] = 1;
for(int i=2;i<=n;i++){
while(head!=tail&&a[que[tail-1]]<a[i]) big[que[tail-1]] = i,tail--;
que[tail++] = i;
}
while(head!=tail) big[que[head++]] = n+1;
head = tail = 1e7;
int s = n-m+1,d = big[1];
que[tail++] = 1;
while(d<=m){
que[tail++] = d;
d = big[d];
}
ll A = a[que[tail-1]]^1;
ll B = (tail-head+(que[head]?0:-1))^1;
for(int i=2;i<=s;i++){
head++;
if(a[i]<=a[i-1]){
int eng = que[head];
if(tail==head){
int u = big[i],v = i+m-2;
que[--head] = i;
while(u<=v) que[tail++] = u,u = big[u];
}else{
int u = big[i];top = 0;
while(u<eng) num[top++] = u,u = big[u];
for(int j=top-1;j>=0;j--) que[--head] = num[j];
que[--head] = i;
}
}
if(a[i+m-1]>a[que[tail-1]]) que[tail++] = i+m-1;
A += a[que[tail-1]]^i;
B += (tail-head+(que[head]?0:-1))^i;
}
printf("%lld %lld\n",A,B);
}
return 0;
}