Gushing over Programming Girls|

BigSmall_En

园龄:3年2个月粉丝:3关注:5

2025-02-11 19:35阅读: 2评论: 0推荐: 1

LG5504 [JSOI2011] 柠檬 题解

LG5504 [JSOI2011] 柠檬

\(\text{Flute}\) 很喜欢柠檬。它准备了一串用树枝串起来的贝壳,打算用一种魔法把贝壳变成柠檬。贝壳一共有 \(n\) \((1≤n≤100000)\) 只,按顺序串在树枝上。为了方便,我们从左到右给贝壳编号 \(1..n\) 。每只贝壳的大小不一定相同,贝壳 \(i\) 的大小为 \(a_i(1≤a_i≤10000)\)

变柠檬的魔法要求\(:\ \text{Flute}\) 每次从树枝一端取下一小段连续的贝壳,并选择一种贝壳的大小 \(a_0\)。如果这一小段贝壳中大小为 \(a_0\) 的贝壳有 \(t\) 只,那么魔法可以把这一小段贝壳变成 \(a_0t^2\) 只柠檬。\(\text{Flute}\) 可以取任意多次贝壳,直到树枝上的贝壳被全部取完。各个小段中,\(\text{Flute}\) 选择的贝壳大小 \(a_0\) 可以不同。而最终 \(\text{Flute}\) 得到的柠檬数,就是所有小段柠檬数的总和。

\(\text{Flute}\) 想知道,它最多能用这一串贝壳变出多少柠檬。请你帮忙解决这个问题。

显然每一段两端的贝壳大小相等是最优的,否则可以额外增加一段产生贡献。

\(dp_i\) 表示前 \(i\) 个贝壳的答案,\(s_i\) 表示前 \(i\) 个贝壳中与 \(a_i\) 相等的贝壳个数。然后假设 \(dp_i\) 可以从 \(dp_j,dp_k\) 转移得到(不妨 \(k<j<i\)),有

\[dp_i=\max(dp_j+a_i\times(s_i-s_j)^2,dp_k+a_i\times(s_i-s_k)^2) \]

当从 \(j\) 转移更优时,有

\[dp_j+a_i\times (s_i-s_j)^2>dp_k+a\times (s_i-s_k)^2\\ dp_j+a_i s_i^2-2a s_is_j+as_j^2>dp_k+as_i^2-2as_is_k+as_k^2\\ (dp_j+as_j^2)-(dp_k+as_k^2)>2as_i(s_j-s_k)\\ \frac{(dp_j+as_j^2)-(dp_k+as_k^2)}{s_j-s_k}>2as_i \]

然后把 \((s_i,dp_j+as_j^2)\) 看作决策点,使用单调栈维护上凸包即可。

其他就是实现问题,然而写了快 \(2\) 个小时,发现自己写得真的丑,学习别人的又写了一版。(理论上斜率用 double 写会更直观,不过怕掉精度就没用)

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef pair<int,int>ttfa;
const int N=200005;

int n,a[N],num[N];
ll sum[N],yval[N],xval[N],dp[N];
vector<int>stk[N];

#define t1 stk[v][stk[v].size()-1]
#define t2 stk[v][stk[v].size()-2]

int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;++i){
		scanf("%d",&a[i]);
		sum[i]=++num[a[i]];
	}
	stk[a[1]].push_back(0);
	for(int i=1;i<=n;++i){
		ll v=a[i];
		while(stk[v].size()>=2&&yval[t1]-yval[t2]<=2*v*sum[i]*(xval[t1]-xval[t2]))
			stk[v].pop_back();
		dp[i]=dp[t1]+v*(sum[i]-xval[t1])*(sum[i]-xval[t1]);
		v=a[i+1];
		xval[i]=sum[i+1]-1;yval[i]=dp[i]+v*xval[i]*xval[i];
		while(stk[v].size()>=2&&(yval[i]-yval[t1])*(xval[t1]-xval[t2])>(yval[t1]-yval[t2])*(xval[i]-xval[t1]))
			stk[v].pop_back();
		stk[v].push_back(i);
	}
	printf("%lld\n",dp[n]);
	return 0;
}

贴到博客上来提醒一下自己。

本文作者:BigSmall_En

本文链接:https://www.cnblogs.com/BigSmall-En/p/18710358

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   BigSmall_En  阅读(2)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起