HDU - 6319 Ascending Rating【单调队列】
ai=(p×ai−1+qai=(p×ai−1+q
题目链接:https://vjudge.net/problem/HDU-6319ai=(p×ai−1+q
题意:给你n,m,k,p,q,r,MOD,七个数,n为长度为n的数组,其中前k个数已经给出,后面的按照公式补足。
问每长度为m的区间中最大值的位置和从左到右最大值更新了多少次
答案按输出公式进行异或
思路:一开始想到的单调区间,但是是从左到右依次遍历i,然后再从第i个往前搜索m个数,过于复杂,导致做不出
应当是从右往左依次遍历,这样一次即可,单调队列中按从大到小排列,如果a[i]一直比队列末尾的数大,末尾数就一直出队
否则a[i]入队,此时队列中头元素就是区间m中最大值,队列中有多少个就是区间m中最大值更新次数
#define _CRT_SECURE_NO_WARNINGS #include<iostream> #include<cstring> #include<stdio.h> #include<algorithm> #include<map> #include<queue> #include<set> #include <sstream> #include<vector> #include<cmath> #include<stack> using namespace std; #define io ios::sync_with_stdio(0),cin.tie(0) #define ms(arr) memset(arr,0,sizeof(arr)) #define LD long double #define LL long long #define PI acos(-1.0) #define INF 0x3f3f3f3f #define inf 1<<30 #define ull unsigned long long const int Mod = 998244353; const int maxn = 1e7 + 9; int read() { int x = 0, f = 1; char ch = getchar(); while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); } while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); } return x * f; } int a[maxn]; int Q[maxn]; int n, m, q, p, k, r, mod, t; int head, tail; LL ans1, ans2; int main() { t = read(); while (t--) { n = read(); m = read(); k = read(); p = read(); q = read(); r = read(); mod = read(); for (int i = 1; i <= k; i++) {//读入前k个数 a[i] = read(); } for (int i = k + 1; i <= n; i++) {//按照公式补足数组 a[i] = (1ll * p * a[i - 1] + 1ll * q * i + r) % mod; } head = 1; tail = 0;//初始化 ans1 = ans2 = 0; for (int i = n; i > 0; i--) {//从右往左遍历 while (tail >= head && a[Q[tail]] <= a[i])tail--;//队尾元素比a[i]小就出队 Q[++tail] = i;//a[i]入队 if (i + m - 1 <= n) {//形成了一个大小为m的区间 while (Q[head] >= i + m)head++;//队首元素已经不在当前m区间范围,出队 ans1 += i ^ a[Q[head]];//记录答案 ans2 += i ^ (tail - head + 1); } } cout << ans1 << " " << ans2 << endl; } }