题意:
an 和 bn 是两个长度为 n 的序列,其中保证 1 <= bi <= n,
现要求根据 bn 来补全 an+1 ~ a2n 的数字,要求这一段和最大,
补全规则如下:
补 ai 时,从 bn 中不重复地挑选一个数字 bk, 要求 ai <= max { aj - j | bk <= j < i },
思路:
我们看补全规则,就是在说从 ai 中下标为 bk 的地方起一直向后到现有的最后一个位置中,找一个 aj - j 的最大值
因为 ai <= aj - j,
所以 ai - i < aj - j,
所以对于 an+1 ~ a2n 而言,这一段的 aj - j 值是 递减 的
显然,我们需要维护一个 maxa[1..n](因为保证了1 <= bi <= n),
maxa[i] 意为从第 i 个位置起一直到当前位置的 aj - j 的最大值,
又因为 an+1 ~ a2n 这一段的该值是递减的,所以随着 i 的位置向后移,这个数组的值事实上是压根 不需要更新 的
但有一点要 注意 ,
就是 i = n + 1 时,是需要用 an+1 - (n+1) 去更新 maxa 的,因为这一段是开始递减的第一个值,它的值是可能比前面记录的值大的
当 i > n + 1 时,就不需要更新了
那么还剩下最后一个问题,该以什么顺序取 bk 呢?
其实我觉得挺显然的,直接 按 bk 的值从小到大就可行,
其实吧,只需要保证 an+1 - (n+1) 的值是 可以取到的最大值 即可,毕竟之后都不会再更新了
而按 bk 的值从小到大取,即可以保证每次在 a 中能取的范围逐渐缩小,取 an+1 时范围最大,很显然可以满足上述要求
时间复杂度O(n)
AC代码如下:
#include <cstdio>
#include <algorithm>
#include <iostream>
#define maxn 250010
typedef long long LL;
const LL mod = 1e9 + 7;
using namespace std;
int a[maxn], b[maxn], maxa[maxn], diff[maxn], n;
inline int max(int a, int b) { return a > b ? a : b; }
void work() {
for (int i = 1; i <= n; ++i) { scanf("%d", &a[i]); diff[i] = a[i] - i; }
for (int i = 1; i <= n; ++i) scanf("%d", &b[i]);
maxa[n] = diff[n];
for (int i = n - 1; i > 0; --i) maxa[i] = max(maxa[i + 1], diff[i]);
sort(b + 1, b + 1 + n);
int x = maxa[b[1]];
LL ans = x;
for (int i = 1; i <= n; ++i) maxa[i] = max(maxa[i], x - (n + 1));
for (int i = 2; i <= n; ++i) {
x = maxa[b[i]];
ans += (LL)x;
ans %= mod;
}
printf("%lld\n", ans);
}
int main() {
while (scanf("%d", &n) != EOF) work();
return 0;
}