(2017多校2)1003/hdu-6047 Maximum Sequence(单调队列/优先队列)

来源:互联网 发布:西班牙手机网络 编辑:程序博客网 时间:2024/06/08 11:19

点我看题

题意:分别给出两个序列a和b,根据规则ai≤max{aj-j│bk≤j<i}(其中n<i<=2*n),求得一个序列an+1-a2n,要求其总和最大.

官方题解:预处理:a_i -= i ,易证明从最小的b开始选每次选最大的一定可以使结果最大。 证明思路:如果条件改为a_i<=max{a_j-j|b_k<=j<=n},那么b的顺序与最后的结果无关。条件改回来后,由于每次要计算一个数的最大值时都有a_(n+1)...a_(i-1)在范围中,所以每次只需让a_i - i尽可能大,那么就把大的数尽早用上,每次一定考虑尽量多的数字,这样取得的数字就尽可能的大。 所以说每次就是求区间最值,加在答案上。由于贪心的思路,每次要求的区间的下界是单调不降的,故可以用单调队列优化到O(n)的复杂度。 由于1 ≤ b_i ≤ n,对b排序可以用哈希排序(桶排序)完成。

进一步观察,可以发现这样贪心时 a_(n+1)...a_i 其实是单调不增的,所以并不需要每次求区间最值了,选第一个数时就选最大的,后面的选择顺序与最终结果无关了

分析:Contest的时候用优先队列写的,当时比较担心超时,后来想想应该也不会超时,因为进队出队的过程都是O(log2n),不过后来发现用单调队列更节约时间.


参考代码:

//优先队列

#include<iostream>#include<cstdio>#include<cstring>#include<cmath>#include<string>#include<algorithm>#include<queue>#include<stack>#include<set>#include<map>#include<vector>using namespace std;typedef long long ll;const int maxn = 250010;const int mod = 1e9+7;int n;int a[maxn];int b[maxn];struct Node{    int val;    int id;    friend bool operator < ( const Node &a, const Node &b)    {        if( a.val != b.val)            return a.val < b.val;        return a.id > b.id;    }};priority_queue<Node> q;int main(){    while( ~scanf("%d",&n))    {        while( !q.empty())            q.pop();        Node tmp;        for( int i = 1; i <= n; i++)        {            scanf("%d",&a[i]);            tmp.id = i;            tmp.val = a[i]-i;            q.push(tmp);        }        for( int i = 1; i <= n; i++)            scanf("%d",&b[i]);        sort(b+1,b+1+n);        ll ans = 0;        int p = 1;        while( p <= n)        {            tmp = q.top();            while( b[p] > tmp.id)            {                q.pop();                tmp = q.top();            }            ans=(ans+tmp.val)%mod;            tmp.val -= (n+p);            tmp.id = n+p;            q.push(tmp);            p++;        }        printf("%lld\n",ans);    }    return 0;}

//单调队列

#include<cstdio>#include<cmath>#include<cstring>#include<algorithm>#include<iostream>using namespace std;#define LL long longconst int mod = 1e9+7;const int maxn = 250010;int n;int a[maxn];int b[maxn];struct Node{    int id;    int val;};Node q[maxn<<1];int main(){    while( ~scanf("%d",&n))    {        int head = 0;        int tail = 0;        for( int i = 1; i <= n; i++)        {            scanf("%d",&a[i]);            if( tail == 0)            {                q[tail].id = i;                q[tail++].val = a[i]-i;            }            else            {                while( head < tail && a[i]-i >= q[tail-1].val)                    tail--;                q[tail].id = i;                q[tail++].val = a[i]-i;            }        }        for( int i = 1; i <= n; i++)            scanf("%d",&b[i]);        sort(b+1,b+1+n);        int p = 1;        Node tmp;        LL ans = 0;        while( p <= n)        {            while( b[p] > q[head].id)                head++;            ans = (ans+q[head].val)%mod;            tmp.id = p+n;            tmp.val = q[head].val-(n+p);            while( head < tail && tmp.val >= q[tail-1].val)                tail--;            q[tail++] = tmp;            p++;        }        printf("%lld\n",ans);    }    return 0;}