2018 Multi-University Training Contest 3 1001 / hdu6319 Problem A. Ascending Rating 单调队列,思维

Problem A. Ascending Rating

题意:
给定一个序列a[1..n],对于所有长度为m的连续子区间,求出区间的最大值以及从左往右扫描该区间时a的最大值的变化次数。
1≤m≤n≤107。 Shortest judge solution: 534 bytes
题解:
官方题解:按照r从m到n的顺序很难解决这个问题。考虑按照r从n到m的顺序倒着求出每个区间的答案。按照滑窗最大值的经典方法维护a的单调队列,那么队列中的元素个数就是最大值的变化次数。时间复杂度O(n)。
最大值好算,就是变化次数要想到从后往前推。


#include<bits/stdc++.h>
using namespace std;
#pragma comment(linker, "/STACK:102400000,102400000")
#define rep(i,a,b) for (int i=a; i<=b; ++i)
#define per(i,b,a) for (int i=b; i>=a; --i)
#define mes(a,b)  memset(a,b,sizeof(a))
#define INF 0x3f3f3f3f
#define MP make_pair
#define PB push_back
#define fi  first
#define se  second
typedef long long ll;
const int N = 10000005;

#define  pii  pair<int, int>
int a[N], n, m, k, p, q, r, mod;
deque< pii  > DQ;
int main()
{
    int T;  scanf("%d", &T);
    while(T--)
    {
        DQ.clear();
        scanf("%d%d%d%d%d%d%d", &n, &m, &k, &p, &q, &r, &mod);
        rep(i,1,k) scanf("%d", &a[i]);
        rep(i,k+1,n) a[i] = (1LL*p*a[i-1] + 1LL*q*i+r) %mod;
        ll  ans1=0, ans2=0;
        per(i,n,1)
        {
            if(DQ.empty()) DQ.push_front(MP(a[i],i));
            else  {
                while(!DQ.empty() && DQ.front().fi<=a[i]) DQ.pop_front();
                DQ.push_front(MP(a[i],i));
            }
            if(i+m-1 < DQ.back().se) DQ.pop_back();
            if(i <= n-m+1)
                ans1 += DQ.back().fi^i,  ans2 += DQ.size()^i;
        }
        printf("%lld %lld\n", ans1, ans2);
    }

    return 0;
}
posted @ 2018-08-02 22:25  v9fly  阅读(131)  评论(0编辑  收藏  举报