Maximum Sequence
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1750 Accepted Submission(s): 813
Given two integer sequences {ai} and {bi} with the same length n, you are to find the next n numbers of {ai}: an+1…a2n. Just like always, there are some restrictions on an+1…a2n: for each number ai, you must choose a number bk from {bi}, and it must satisfy ai≤max{aj-j│bk≤j<i}, and any bk can’t be chosen more than once. Apparently, there are a great many possibilities, so you are required to find max{∑2nn+1ai} modulo 109+7 .
Now Steph finds it too hard to solve the problem, please help him.
For each test case, the first line consists of one integer n. The next line consists of n integers representing {ai}. And the third line consists of n integers representing {bi}.
1≤n≤250000, n≤a_i≤1500000, 1≤b_i≤n.
/*
题目大意:
长度都为n的a,b数组,现在要把a数组的长度变成2n。
向a数组中添加元素满足:
对于每一个加入i位置的元素x,必须满足x<=max{a[j] - j│b[k] ≤ j < i},
求问增加的所有元素之和最大值是多少(答案对10^9+7取模)
题解:
贪心+单调队列:按照b数组从小到大的顺序,选取a中的元素,同时用单调队列维护当前的最大值
官方题解:
预处理: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 其实是单调不增的,所以并不需要每次求区间最值了,
选第一个数时就选最大的,后面的选择顺序与最终结果无关了。
*/
#include <iostream> #include <algorithm> #include <cstdio> #include <cstring> #include <queue> using namespace std; typedef long long LL; const int N = 500000 + 100; const LL mod = 1e9 + 7; int a[N], b[N]; struct node { int val, id; } t, q[N]; int main() { int n; while(~scanf("%d", &n)) { int tp = 0, ed = 0; for(int i = 1; i <= n; i++) { scanf("%d", &a[i]); a[i] -= i; t.id = i, t.val = a[i]; //维护当前最大值 if(i > 1) { while(tp < ed && a[i] >= q[ed - 1].val) ed--; } q[ed++] = t; } for(int i = 1; i <= n; i++) { scanf("%d", &b[i]); } //贪心 sort(b + 1, b + n + 1); LL ans = 0; //维护当前最大值 for(int i = n + 1; i <= 2 * n; i++) { //满足条件b[k] ≤ j < i while(b[i - n] > q[tp].id) tp++; ans = (ans + q[tp].val) % mod; t.id = i, t.val = q[tp].val - i; while(tp < ed && q[ed - 1].val <= t.val) ed--; q[ed++] = t; } printf("%lld\n", ans); } return 0; }