HDU 6319题解(数据结构之双端队列)

版权声明:本文为博主原创文章,未经博主允许不得转载。 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;
}

猜你喜欢

转载自blog.csdn.net/Q1410136042/article/details/81301788