hdu 6047

思路出自此。点击打开链接  。 这题我看到很多维护用的是线段树,但是这个博主给了我很多提示。(其实是我不会线段树-_-)

题意:给出一个数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
#include
#include
#include
#include
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 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;
}



你可能感兴趣的:(hdu)