洛谷P3195 [HNOI2008]玩具装箱TOY

题面
大意:自己看太复杂我不想解释了


终于,我要开始复习我目前接触到的最毒瘤、思考难度最大的算法了。
斜率优化。
简单介绍一下: 斜率优化在我看来就是利用一个玄学的方法确定一个值,然后用这个值去确定以前的一些状态是否没有用,再结合单调队列或其他数据结构减少DP过程中的继承次数,从而达到加速的目的。 不得不说斜率优化必!须!得!数!形!结!合!

斜率优化是将每一个状态转换成决策点,再用求最小截距等方法加速的

废话少说我们来做题

首先我们可以飞快地想出 O ( n 2 ) O(n^2) O(n2)的算法:
f [ i ] f[i] f[i]表示前 i i i个玩具被装好的最小花费
然后
f [ i ] = min ⁡ j = 0 i − 1 ( f [ j ] + ( i − j − 1 + ∑ k = j + 1 i a [ i ] − L ) 2 ) f[i]=\min\limits^{i-1}_{j=0}(f[j]+(i-j-1+\sum\limits^{i}_{k=j+1}a[i]-L)^2) f[i]=j=0mini1(f[j]+(ij1+k=j+1ia[i]L)2)
即将第 j + 1 j+1 j+1到第 i i i个放到一个盒子中
(请原谅我用了一种玄学的方式表示求最小值)
其中 ∑ k = j + 1 i a [ i ] \sum\limits^{i}_{k=j+1}a[i] k=j+1ia[i]一部分可以用前缀和求

#incLude<cstdio>
#incLude<cstring>
using namespace std;
Long Long min(register Long Long a,register Long Long b)
{return a<b?a:b;}
Long Long sqr(register Long Long x)
{return x*x;}
int a[51000],sum[51000];
Long Long f[51000];
int main()
{
	int n,l;
	scanf("%d%d",&n,&l);
	for(int i=1;i<=n;i++)
		scanf("%d",a+i),sum[i]=sum[i-1]+a[i];
	memset(f,1,sizeof(f));
	f[0]=0;
	for(int i=1;i<=n;i++)
		for(int j=0;j<n;j++)
			f[i]=min(f[i],f[j]+sqr(i-j-1+(sum[i]-sum[j])-l));
	printf("%LLd",f[n]);
	return 0;
}

可以成功地获得20分


接下来优化的时间就到了
首先,我们从状态转移方程入手:

f[i]=min(f[i],f[j]+sqr(i-j-1+(sum[i]-sum[j])-l));

可以发现,记 s [ i ] = s u m [ i ] + i s[i]=sum[i]+i s[i]=sum[i]+i L = L + 1 L=L+1 L=L+1可以简化方程
则有:

f[i]=min(f[i],f[j]+sqr(s[i]-s[j]-l));

然后我们开始数形结合

(PS.:本来这后面有一段两千多字打了我整整一天的推导,最后发现根本**不通——请原谅我因为实在是太生气了)(数形结合万岁!

简单地讲,现在优化的目的就是尽快地找到这个使 f i f_i fi最小化的 j j j
所以,我们设 j j j就是令 f i f_i fi最小化的继承状态
f i = f j + ( s i − s j − L ) 2 f_i=f_j+(s_i-s_j-L)^2 fi=fj+(sisjL)2
将这个方程展开,并将其转化为 y = k x + b y=kx+b y=kx+b的形式
其中, y y y x x x要包含所有与 j j j有关的项,且 x x x要保证随 j j j单调递增(方便构建模型), k , b k,b k,b是与 j j j无关的值, b b b要包含 f i f_i fi
原 式 = f i = f j + s i 2 − 2 s i ( s j + L ) + ( s j + L ) 2 原式=\qquad\qquad f_i=f_j+{s_i}^2-2s_i(s_j+L)+(s_j+L)^2 =fi=fj+si22si(sj+L)+(sj+L)2
f i − s i 2 = f j − 2 s i ( s j + L ) + ( s j + L ) 2 f_i-{s_i}^2=f_j-2s_i(s_j+L)+(s_j+L)^2 fisi2=fj2si(sj+L)+(sj+L)2
f i − s i 2 + 2 s i ( s j + L ) = f j + ( s j + L ) 2 f_i-{s_i}^2+2s_i(s_j+L)=f_j+(s_j+L)^2 fisi2+2si(sj+L)=fj+(sj+L)2
即 f j + ( s j + L ) 2 = 2 s i ( s j + L ) + f i − s i 2 即f_j+(s_j+L)^2=2s_i(s_j+L)+f_i-{s_i}^2 fj+(sj+L)2=2si(sj+L)+fisi2
其中:
y = f j + ( s j + L ) 2 y=f_j+(s_j+L)^2 y=fj+(sj+L)2
k = 2 s i k=2s_i k=2si
x = s j + L x=s_j+L x=sj+L
(由 2 s i ( s j + L ) 2s_i(s_j+L) 2si(sj+L)拆成)
b = f i − s i 2 b=f_i-{s_i}^2 b=fisi2

这样,我们就得到了对于 j j j的坐标描述: ( s j + L , f j + ( s j + L ) 2 ) (s_j+L,f_j+(s_j+L)^2) (sj+L,fj+(sj+L)2)
不逼逼上图

就是这样,我们要找到一个点把那条线挂上去
线的斜率不变,又需要挂在最低的地方
点从左到右依次加入
观察一下,除了图中的那几个折线上的点,其它点想都不用想就可以淘汰:

因为它们被挡住了。
而再观察这条折线,上面任意的三个点 A , B , C A,B,C A,B,C若满足 x A < x B < x C x_A<x_B<x_C xA<xB<xC,就有 A B AB AB的斜率小于 B C BC BC的斜率。(记任意两点 B , C B,C B,C的斜率为 slop ⁡ ( B , C ) \operatorname{slop}(B,C) slop(B,C)
结合点的加入方式和最优化的需求,考虑 O ( 1 ) O(1) O(1)查询最值+末端插入的单调队列
(记单调队列为 q q q,队尾下标为 t a i l tail tail,队头下标为 h e a d head head,新加入的点为 i i i
推出淘汰队列末尾的标准:
slop ⁡ ( q t a i l − 1 , q t a i l ) ≥ slop ⁡ ( q t a i l , i ) \operatorname{slop}(q_{tail-1},q_{tail})\ge\operatorname{slop}(q_{tail},i) slop(qtail1,qtail)slop(qtail,i)时,剔除 q t a i l q_{tail} qtail

而又从单调队列引出一个问题:如何删队头?
这简单:由图可知斜率小于 k k k的就删掉证明很简单但我很懒
如果以后的直线斜率比现在小了怎么办?
k = 2 s i k=2s_i k=2si—— s i s_i si是和 i i i一起递增的。

由此,单调队列所有操作全部推出。

代码:

#include<cstdio>
#define ll long long
using namespace std;
int l;
struct deque
{
	int list[51000];
	int head,tail;//head~tail
	
	deque():head(1),tail(0){}
	int size(){return tail-head+1;}
	
	int front(){return list[head];}
	void push_front(int x){list[--head]=x;}
	void pop_front(){++head;}
	int front_2nd(){return list[head+1];}
	
	int back(){return list[tail];}
	void push_back(int x){list[++tail]=x;}
	void pop_back(){--tail;}
	int back_2nd(){return list[tail-1];}
};
ll sqr(ll x)
{return x*x;}
int a[51000];
ll s[51000];
ll f[51000];
double slop(ll a,ll b)
{return (f[b]+sqr(s[b]+l)-f[a]-sqr(s[a]+l))/(double)(s[b]-s[a]);}
int main()
{
	int n;
	scanf("%d%d",&n,&l);l++;
	for(int i=1;i<=n;i++)
		scanf("%d",a+i),s[i]=s[i-1]+a[i]+1;
	deque q;
	q.push(0);//很重要!!!要初始化!!!
	f[0]=0;
	for(int i=1;i<=n;i++)
	{
		while(q.size()>1&&slop(q.front(),q.front_2nd())<=2*s[i])q.pop_front();
		f[i]=f[q.front()]+sqr(s[i]-s[q.front()]-l);
		while(q.size()>1&&slop(q.back_2nd(),q.back())>=slop(q.back(),i))q.pop_back();
		q.push_back(i);
	}
	printf("%lld",f[n]);
	return 0;
}

参考资料:LB不顶用

内容概要:《中文大模型基准测评2025年上半年报告》由SuperCLUE团队发布,详细评估了2025年上半年中文大模型的发展状况。报告涵盖了大模型的关键进展、国内外大模型全景图及差距、专项测评基准介绍等。通过SuperCLUE基准,对45个国内外代表性大模型进行了六大任务(数学推理、科学推理、代码生成、智能体Agent、精确指令遵循、幻觉控制)的综合测评。结果显示,海外模型如o3、o4-mini(high)在推理任务上表现突出,而国内模型如Doubao-Seed-1.6-thinking-250715在智能体Agent和幻觉控制任务上表现出色。此外,报告还分析了模型性价比、效能区间分布,并对代表性模型如Doubao-Seed-1.6-thinking-250715、DeepSeek-R1-0528、GLM-4.5等进行了详细介绍。整体来看,国内大模型在特定任务上已接近国际顶尖水平,但在综合推理能力上仍有提升空间。 适用人群:对大模型技术感兴趣的科研人员、工程师、产品经理及投资者。 使用场景及目标:①了解2025年上半年中文大模型的发展现状与趋势;②评估国内外大模型在不同任务上的表现差异;③为技术选型和性能优化提供参考依据。 其他说明:报告提供了详细的测评方法、评分标准及结果分析,确保评估的科学性和公正性。此外,SuperCLUE团队还发布了多个专项测评基准,涵盖多模态、文本、推理等多个领域,为业界提供全面的测评服务。
根据引用\[1\]和引用\[2\]的描述,题目中的影魔拥有n个灵魂,每个灵魂有一个战斗力ki。对于任意一对灵魂对i,j (i<j),如果不存在ks (i<s<j)大于ki或者kj,则会为影魔提供p1的攻击力。另一种情况是,如果存在一个位置k,满足ki<c<kj或者kj<c<ki,则会为影魔提供p2的攻击力。其他情况下的灵魂对不会为影魔提供攻击力。 根据引用\[3\]的描述,我们可以从左到右进行枚举。对于情况1,当扫到r\[i\]时,更新l\[i\]的贡献。对于情况2.1,当扫到l\[i\]时,更新区间\[i+1,r\[i\]-1\]的贡献。对于情况2.2,当扫到r\[i\]时,更新区间\[l\[i\]+1,i-1\]的贡献。 因此,对于给定的区间\[l,r\],我们可以根据上述方法计算出区间内所有下标二元组i,j (l<=i<j<=r)的贡献之和。 #### 引用[.reference_title] - *1* *3* [P3722 [AH2017/HNOI2017]影魔(树状数组)](https://blog.youkuaiyun.com/li_wen_zhuo/article/details/115446022)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [洛谷3722 AH2017/HNOI2017 影魔 线段树 单调栈](https://blog.youkuaiyun.com/forever_shi/article/details/119649910)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值