【題解】Oh My Holy FFF

題目大意

  有\(n\)個士兵(\(1 \leq n \leq 10^5\)),第\(i\)個士兵的身高爲\(h_{i}\),如今要求把士兵按照原來的順序分紅連續的若干組,要求每組的士兵數量不超過\(len\)
  同時,咱們設每組的最後一個士兵的身高爲\(b_{i}\),則有\(b_{i} > b_{i - 1}\)\(b_0 = 0\)),如今咱們設每種分組方案的價值爲\(\sum b_{i}^2 - b_{i - 1}\),求能獲得的最大價值爲多少?ios

題解

  咱們設\(dp[i]\)表示前\(i\)個士兵分紅任意組的最大價值,容易獲得:
\[dp[i] = \underset{i - len \leq j < i}{\max} \{ dp[j] + k_{i}^2 - k_{j} \}\]
  整理一下,獲得:
\[dp[i] = k_{i}^2 + \underset{i - len \leq j < i}{\max} \{ dp[j] - k_{j} \}\]
  咱們能夠用線段樹來維護\(\underset{i - len \leq j < i}{\max} \{ dp[j] - k_{j} \}\).
  可是。如何保證題目中要求的\(b_{i} > b_{i - 1}\)呢?
  其實,對於每一個士兵,咱們能夠先按照身高來進行升序排列,若是身高相同,咱們就按照編號(原來的順序)降序排列,而後對於排序後的士兵\(i\),咱們設他原來的編號爲\(idx_{i}\),則咱們就查找線段樹上\([idx_{i} - len, idx_{i} - 1]\)的價值,同時更新也是更新線段樹上的\(idx_{i}\)的位置。
  由於對於每一個士兵\(i\),若是在排序前能找到和他進行狀態轉移的士兵\(j\),那麼排序後,確定有\(idx_{j} \in [idx_{i} - len, idx_{i} - 1]\),這個你們能夠本身試幾個狀況,因此這樣作便可。git

#include <iostream>
#include <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>

#define MAX_N (100000 + 5)
#define SIZE (1 << 21)

#define lowbit(x) ((x) & -(x))
#define Getchar() (p1 == p2 && (p2 = (p1 = fr) + fread(fr, 1, SIZE, stdin), p1 == p2) ? EOF : *p1++)

using namespace std;

char fr[SIZE], * p1 = fr, * p2 = fr;

void Read(int & res)
{
    res = 0;
    char ch = Getchar();
    while(!isdigit(ch)) ch = Getchar();
    while(isdigit(ch)) res = res * 10 + ch - '0', ch = Getchar();
    return;
}

struct Node
{
    int h;
    int idx;
    friend inline bool operator < (Node a, Node b)
    {
        if(a.h != b.h) return a.h < b.h;
        return a.idx > b.idx;
    }
};

int T;
int n, len;
Node a[MAX_N];
long long s[MAX_N << 2];

void Modify(int x, int l, int r, int pos, long long val)
{
    if (r < pos || pos < l) return;
    if (l == r)
    {
        s[x] = val;
        return;
    }
    int mid = l + r >> 1;
    Modify(x << 1, l, mid, pos, val);
    Modify(x << 1 | 1, mid + 1, r, pos, val);
    s[x] = max(s[x << 1], s[x << 1 | 1]);
    return;
}

long long Query(int x, int l, int r, int L, int R)
{
    if (r < L || R < l) return -0x7f7f7f7f7f7f7f7f;
    if (L <= l && r <= R) return s[x]; 
    int mid = l + r >> 1;
    return max(Query(x << 1, l, mid, L, R), Query(x << 1 | 1, mid + 1, r, L, R));
}

int main()
{
    Read(T);
    for (int I = 1; I <= T; ++I)
    {
        memset(s, -0x7f, sizeof s);
        Read(n); Read(len);
        for (int i = 1; i <= n; ++i)
        {
            Read(a[i].h);
            a[i].idx = i;
        }
        sort(a + 1, a + n + 1);
        long long tmp;
        printf("Case #%d: ", I);
        Modify(1, 0, n, 0, 0);
        for (int i = 1; i <= n; ++i)
        {
            tmp = Query(1, 0, n, max(0, a[i].idx - len), a[i].idx - 1);
            if (tmp < -0x7f7f7f7f)
            {
                if (a[i].idx == n)
                {
                    printf("No solution\n");
                    break;
                }
                continue;
            }
            if (a[i].idx == n)
            {
                printf("%lld\n", (long long)a[i].h * a[i].h + tmp);
                break;
            }
            Modify(1, 0, n, a[i].idx, (long long)a[i].h * a[i].h + tmp - a[i].h);
        }
    }
    return 0;
}
相關文章
相關標籤/搜索