hdu 6319 逆序建单调队列

题目传送门//res tp hdu

维护递增单调队列
根据数据范围推测应为O(n)的.
我们需要维护一个区间的信息,区间内信息是“有序”的,同时需要在O(1)的时间进行相邻区间的信息转移.
若是主数列从头到尾转移无法有解题突破口,就反过来从尾到头再思考.

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define per(i,a,b) for(int i = (a);i>=(b);--i)
#define fo(i,a,b) for(int i =(a);i<(b);++i)
#define de(x) cout<<#x<<" = "<<x<<endl;
#define endl '\n'
#define ls(p) ((p)<<1)
#define rs(p) (((p)<<1)|1)
using namespace std;
typedef long long ll;
const int mn = 1e7+10;
int T;
ll a[mn];
ll n,m,k,p,q,r,MOD;
int L,R;
int tmaxr;
ll A,B;
ll val[mn];
int pos[mn];
int main(){
	scanf("%d",&T);
	while(T--){
		A = B = 0;
		scanf("%lld %lld %lld %lld %lld %lld %lld",&n,&m,&k,&p,&q,&r,&MOD);
		rep(i,1,k)	scanf("%lld",&a[i]);
		if(k<n)
		rep(i,k+1,n) a[i] = (p*a[i-1]+q*i+r)%MOD;
		L = R = n-m+1;
		val[L] = a[L]; pos[L] = L;
		tmaxr = a[L];
		int tem = n-m+2;
		rep(i,tem,n) if(a[i] > tmaxr){
			++R;
			val[R] = a[i]; pos[R]=i;
			tmaxr = a[i];
		}
		A += L^tmaxr;
		B += L^(R-L+1);
		tem-=2;
		per(i,tem,1){
			while(L<=R&&pos[R] > i + m - 1){
					R--;
			}
			if(a[i] >= a[i+1]){
				while(L<=R&&val[L] <= a[i]){
					L++;
				}
			}
			L--;
			val[L]=a[i];pos[L]=i;
			A += val[R]^i;
			B += (R - L + 1)^i;
		}
		printf("%lld %lld\n",A,B);
	}
}
posted @ 2019-09-22 23:20  不学无术/眼高手低  阅读(152)  评论(0编辑  收藏  举报