版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Q1410136042/article/details/81301788
题目链接:看题目点这里~
题意:给定一个序列a[1..n],对于每个长度为m的连续子区间,求出区间a的最大值以及从左往右扫描该区间时a 的最大值的变化次数。(实际上不是输出这个,具体的看原题吧)
1 ≤ m ≤ n ≤ 107
题解:
使用双端队列,由右向左维护一个单调非递减队列。由区间[l, l+m)滑动到[l-1, l+m-1)时,如果a[l-1] <= a[l],则直接给a[l-1]插入到队列首,若a[l-1] > a[i],则从队列首将比a[l-1]小的值pop掉,然后将a[i-1]插到队首。如果a[l+m-1]和队尾元素相等,则将队尾pop掉,如果不等就不用管。每push一个非重复元素,cnt+1,每pop掉一个数字及其所有的重复部分,cnt-1。
这样,每个元素至多都只会被push一次,pop一次,时间复杂度O(n)
AC代码:
#include<iostream>
#include<cstdio>
#include<cmath>
#include<map>
#include<vector>
#include<iomanip>
#include<algorithm>
#include<string>
#include<cstring>
#include<ctime>
#include<queue>
#include<deque>
#define ll long long
#define DEBUG printf("DEBUG\n")
#define FOR(i, s, n) for(int i = s; i < n; ++ i)
#define For(i, s, n) for(int i = s; i > n; -- i)
#define mem(a, n) memset((a), (n), sizeof(a))
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3fLL;
const int mod = 1e9+7;
const int maxn = 1e7+10;
using namespace std;
typedef vector<int> V;
typedef vector<V> VV;
inline void read(int& x)
{
x = 0;
char ch = getchar();
while(ch < '0' || ch > '9') ch = getchar();
while(ch <= '9' && ch >= '0')
{
x = x*10 + ch - 48;
ch = getchar();
}
}
int a[maxn];
int cnt[maxn];
int maxNum[maxn];
int dq[2*maxn];
int head = maxn, tail = maxn;
inline void dqClear() { head = tail = maxn; }
inline void pushFront(const int& x) { dq[-- head] = x; }
inline void pushBack(const int& x) { dq[tail ++] = x; }
inline void popFront() { ++ head; }
inline void popBack() { -- tail; }
inline int getFront() { return dq[head]; }
inline int getBack() { return dq[tail-1]; }
inline bool isEmpty() { return !(tail-head);}
int main()
{
#ifdef AFei
freopen("A.in", "r", stdin);
freopen("A.out", "w", stdout);
#endif // AFei
int T, n, m, k, p, q, r, MOD;
read(T);
while(T --)
{
dqClear();
ll ansA = 0, ansB = 0;
int cnt = 0, maxNum = 0;
// mem(cnt, 0);
// mem(maxNum, 0);
read(n); read(m); read(k); read(p); read(q); read(r); read(MOD);
FOR(i, 1, k+1) read(a[i]);
FOR(i, k+1, n+1) a[i] = (1LL*p*a[i-1] + 1LL*q*i + r) % MOD;
int N = n-m+1;
pushBack(a[N]);
cnt = 1;
maxNum = a[N];
FOR(i, N+1, n+1)
{
if(a[i] > maxNum)
{
++ cnt;
maxNum = a[i];
pushBack(a[i]);
}
else if(a[i] == maxNum)
pushBack(a[i]);
}
ansA += N^maxNum;
ansB += N^cnt;
For(i, N-1, 0)
{
if(a[i+m] == getBack()) popBack();
if(isEmpty())
{
pushBack(a[i]);
cnt = 1;
maxNum = getBack();
ansA += i^maxNum;
ansB += i^cnt;
continue;
}
int tmpMax = maxNum;
maxNum = getBack();
if(maxNum != tmpMax) -- cnt;
if(a[i] < a[i+1])
{
pushFront(a[i]);
++ cnt;
}
else
{
int t;
do
{
t = getFront();
popFront();
if(getFront() != t) -- cnt;
}
while(!isEmpty() && getFront() < a[i]);
pushFront(a[i]);
++ cnt;
maxNum = getBack();
}
ansA += i^maxNum;
ansB += i^cnt;
}
// ll ansA = 0, ansB = 0;
// FOR(i, 1, N+1)
// ansA += maxNum[i]^i, ansB += cnt[i]^i;
printf("%lld %lld\n", ansA, ansB);
}
return 0;
}