列表

详情


NC20193. [JSOI2011]柠檬

描述

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

输入描述

第 1 行:一个整数,表示 N。
第 2 .. N + 1 行:每行一个整数,第 i + 1 行表示 si

输出描述

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

示例1

输入:

5
2
2
5
2
3

输出:

21

说明:

Flute 先从左端取下 4 只贝壳,它们的大小为 2, 2, 5, 2。选择 s0 = 2,那么这一段
里有 3 只大小为 s0 的贝壳,通过魔法可以得到 2×3^2 = 18 只柠檬。再从右端取下最后一
只贝壳,通过魔法可以得到 1×3^1 = 3 只柠檬。总共可以得到 18 + 3 = 21 只柠檬。没有
比这更优的方案了。

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++(g++ 7.5.0) 解法, 执行用时: 26ms, 内存消耗: 5152K, 提交时间: 2023-04-24 21:08:51

#include<bits/stdc++.h>
using namespace std;
#define int long long
int s[100005],cnt[100005],x[100005],y[100005],dp[100005],num[100005];
vector<int>q[100005];
double xie(int a,int b)
{
    return (y[a]-y[b])/(x[a]-x[b]);
}
signed main()
{
    int n;
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>s[i];
        cnt[i]=++num[s[i]];
    }
    for(int i=1;i<=n;i++)
    {
        int w=s[i];
        int l=q[w].size()-1;
        x[i]=w*(cnt[i]-1);
        y[i]=dp[i-1]+w*(cnt[i]-1)*(cnt[i]-1);
        while(l>0&&xie(q[w][l-1],q[w][l])<xie(q[w][l],i))
        {
            q[w].pop_back();l--;
        }
        q[w].push_back(i);
        l++;
        while(l>0&&xie(q[w][l-1],q[w][l])<2*cnt[i])
        {
            q[w].pop_back();l--;
        }
        int temp=q[w][l];
        dp[i]=dp[temp-1]+w*(cnt[i]-cnt[temp]+1)*(cnt[i]-cnt[temp]+1);
    }
    cout<<dp[n]<<endl;
    return 0;
}

C++(clang++11) 解法, 执行用时: 535ms, 内存消耗: 3708K, 提交时间: 2020-11-01 14:04:29

#include<bits/stdc++.h>
#define LL long long
#define pb push_back
using namespace std;
const int N=1e5+5;
int n,a[N];LL dp[N];
vector<int>v[N];
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++)scanf("%d",&a[i]);
	for(int i=1,l,stp,edp;i<=n;i++){
		v[a[i]].pb(i);l=v[a[i]].size()-1;
		stp=max(l-500,0);edp=min(l,10000);
		for(int j=0;j<=edp;j++)dp[i]=max(dp[i],dp[v[a[i]][j]-1]+(LL)a[i]*(l-j+1)*(l-j+1));
		for(int j=stp;j<l;j++)dp[i]=max(dp[i],dp[v[a[i]][j]-1]+(LL)a[i]*(l-j+1)*(l-j+1));
		int pl=0,pr=l;
		while(pl+500<pr){
			int mid=pl+(pr-pl)/3,mid2=pr-(pr-pl)/3;
			LL tv=dp[v[a[i]][mid]-1]+(LL)a[i]*(l-mid+1)*(l-mid+1),tv2=dp[v[a[i]][mid2]-1]+(LL)a[i]*(l-mid2+1)*(l-mid2+1);
			if(tv>tv2)pr=mid2;else pl=mid;
		}
		for(int j=pl;j<=pr;j++)dp[i]=max(dp[i],dp[v[a[i]][j]-1]+(LL)a[i]*(l-j+1)*(l-j+1));
	}
	printf("%lld\n",dp[n]);
	return 0;
}

上一题