zoukankan      html  css  js  c++  java
  • bzoj4709 [Jsoi2011]柠檬

    Description

    Flute很喜欢柠檬。它准备了一串用树枝串起来的贝壳,打算用一种魔法把贝壳变成柠檬。贝壳一共有(N(1le Nle 100000))只,按顺序串在树枝上。为了方便,我们从左到右给贝壳编号 (1...N) 。每只贝壳的大小不一定相同,贝壳 (i) 的大小为 (s_i(1 le s_i le10000)) 。变柠檬的魔法要求,Flute每次从树枝一端取下一小段连续的贝壳,并选择一种贝壳的大小 (s_0) 。如果 这一小段贝壳中 大小为 (s_0) 的贝壳有 (t) 只,那么魔法可以把这一小段贝壳变成 (s_0t^2) 只柠檬。Flute可以取任意多次贝壳,直到树枝上的贝壳被全部取完。各个小段中,Flute选择的贝壳大小 (s_0) 可以不同。而最终 Flute 得到的柠檬数,就是所有小段柠檬数的总和。Flute 想知道,它最多能用这一串贝壳变出多少柠檬。请你帮忙解决这个问题。

    Input

    (1) 行:一个整数,表示 (N)
    (2 ... N + 1) 行:每行一个整数,第 (i + 1) 行表示 (s_i)

    Output

    仅一个整数,表示 Flute 最多能得到的柠檬数。

    Sample Input

    5
    2
    2
    5
    2
    3

    Sample Output

    21

    Solution

    考虑DP, (f[i]) 表示前 (i) 个的最大价值。

    发现每一段的开头结尾应该是同一个颜色才会最优,否则不如单出来选。

    对于 (f[i]),假设之前存在一个点 (j),这个点的颜色 (a[j])(i) 的颜色 (a[i]) 相等,那么我们可以让 (f[i])(j) 转移, (s[i]) 代表前 (i) 个数里 (a[i]) 出现的次数,价值为 $$f[j-1]+a[j] imes (s[i]-s[j]+1)^2$$

    很可以斜率的样子欸...

    #include<bits/stdc++.h>
    using namespace std;
     
    #define N 100001
    #define rep(i, a, b) for (int i = a; i <= b; i++)
    #define ll long long
     
    inline int read() {
        int x = 0, flag = 1; char ch = getchar(); while (!isdigit(ch)) { if (!(ch ^ '-')) flag = -1; ch = getchar(); }
        while (isdigit(ch)) x = (x << 1) + (x << 3) + ch - '0', ch = getchar(); return x * flag;
    }
     
    int n; 
    ll a[N], f[N];
    int cnt[N], s[N];
    vector<int> q[N];
     
    inline ll calc(int x, int y) { return f[x - 1] + a[x] * y * y; }
    inline int k(int x, int y) {
        int l = 1, r = n, mid, ret = n + 1;
        while(l <= r) if(calc(x, (mid = l + r >> 1) - s[x] + 1) >= calc(y, mid - s[y] + 1)) ret = mid, r = mid - 1; else l = mid + 1;
        return ret;
    }
     
    int main() {
         
        n = read();
        rep(i, 1, n) {
            int t = a[i] = read(); cnt[t]++, s[i] = cnt[t];
            while(q[t].size() >= 2 && k(q[t][q[t].size() - 2], q[t][q[t].size() - 1]) <= k(q[t][q[t].size() - 1], i)) q[t].pop_back();
            q[t].push_back(i);
            while(q[t].size() >= 2 && k(q[t][q[t].size() - 2], q[t][q[t].size() - 1]) <= s[i]) q[t].pop_back();
            f[i] = calc(q[t][q[t].size()-1], s[i] - s[q[t][q[t].size()-1]] + 1);
        }
        cout << f[n];
        return 0;
    }
    
  • 相关阅读:
    Android AlertDialog警告对话框实现
    Android状态栏通知Status Bar Notification
    Android spinner控件的实现
    Winform之UI后台线程
    Winform之自定义控件
    WebForm原理,aspx服务器端与客户端源码比较
    IHttpModule之闲扯
    [算法]方正面试题:N×N矩阵螺旋打印输出
    DOTA版设计模式——工厂方法
    Window服务
  • 原文地址:https://www.cnblogs.com/aziint/p/8419030.html
Copyright © 2011-2022 走看看