思路出自此。点击打开链接 。 这题我看到很多维护用的是线段树,但是这个博主给了我很多提示。(其实是我不会线段树-_-)
题意:给出一个数n, 和数组a[1 -> n], b[1 -> n]。要求你求出a[n + 1 -> 2 * n]的和的最大值。要求:对于每一个a[i]],你必须从b数组中选择一个数bk,来推出它。a[i] <= {aj - j | bk <=j < i}。a[i]最大为 a[bk -> i - 1]。b数组中的数,每个只能选一次。
好,我们知道了ai由a[bk -> i - 1]决定,那么我们是不是从求第一个ai就用能求出最大数的bk。求出的ai能够影响之后的ai的值,所以当然从第一个就越大越好。而之后的值并不能影响之前的。这样说吧, 后n个数,如果不考虑求出的值,能由b数组求出的最大数是固定。而你把大的数排前面就能影响他们。
我们需要的值是x = a[i] - i。接下来是实现。用ma[i],表示从i - > n,最大的x。
用优先队列保存xi。
/*
ID: DickensTone
LANG: C++
PROB: palsquare
*/
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
const int maxn = 250000 + 5;
const int mod = 1e9 + 7;
int num[maxn];
int ma[maxn];
int main()
{
//freopen("palsquare.in","r",stdin);
//freopen("palsquare.out","w",stdout);
int n;
while(scanf("%d", &n) == 1)
{
ma[n] = 0;
for(int i = 0; i < n; i++)
{
scanf("%d", &num[i]);
num[i] = num[i] - i - 1;
}
for(int i = n - 1; i >= 0; i--)
ma[i] = max(ma[i + 1], num[i]);
priority_queue<int> q;
for(int i = 0; i < n; i++)
{
int t;
scanf("%d", &t);
q.push(ma[t - 1]);
}
int tmp = 0, ans = 0;//tmp代表以求的ai中最大的有效值x。未求的ai都可以考虑它(不受b数组选择的影响)
for(int i = n + 1; i <= 2 * n; i++)
{
int a = 0;
int t = q.top();
if(tmp > t)
{
a = tmp;
}
else
{
a = t;
}
q.pop();
//printf("%d\n", t);
ans = (ans + a) % mod;
tmp = max(tmp, a - i);
}
printf("%d\n", ans);
}
return 0;
}