“蔚来杯“2022牛客暑期多校训练营5 Don‘t Starve

本文解析了一道关于寻找在给定两点间最优化食物获取路径的问题,通过状态转移方程将时间复杂度从O(n^3)降至O(n^2),展示了动态规划在解决最短路径问题中的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题面:https://ac.nowcoder.com/acm/contest/33190/A

分析 : 因为是求最优化问题,应会想到DP和贪心
然而贪心并不可取,不可以只先走较长的边(的二长的边距离其 他点很远)

我们可以设 d p i , j dp_{i,j} dpi,j为从 i i i开始距离为 j j j时能得到的最多食物
可是在题目中 ( 0 < N < 2001 ) (0<N<2001) (0<N<2001) 而时间复杂度为 O ( n 3 ) O(n^3) O(n3),空间复杂度为 O ( n 4 ) O(n^4) O(n4),显然不可取
实际上,我们可以设 d p i dp_i dpi i i i时能得到的最多食物
so,状态转移方程便为 d p i = m a x ( d p i , d p 所有合法的起点 j + 1 ) dp_i=max(dp_i,dp_{所有合法的起点j}+1) dpi=max(dpi,dp所有合法的起点j+1)
现在,时间复杂度便只为 O ( n 2 ) O(n^2) O(n2),空间复杂度为 O ( n 2 ) O(n^2) O(n2),可以通过这道题了
(对于转移时的存储,见代码)
代码:

#include<bits/stdc++.h>
#define LL long long

using namespace std;

const int MXN=2007;

struct Edge{
	int x,y;
	LL w;
};

Edge p[MXN*MXN];
int x[MXN],y[MXN];
int dp[MXN];

inline int read(){
	int x=0,f=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-'){
			f=-1;
		}
		ch=getchar();
	}
	while(ch>='0'&&ch<='9'){
		x=(x<<3)+(x<<1)+(ch^48);
		ch=getchar();
	}
	return x*f;
}



bool cmp(Edge xx,Edge yy){
	return xx.w>yy.w;
}

int tp[MXN*MXN],top,V[MXN*MXN];

int main(){
	int i,j,k,n,len,res;
	LL v;
	memset(dp,200,sizeof(dp));
	n=read();
	for(i=1;i<=n;i++){
		x[i]=read(); y[i]=read();
	}
	dp[0]=0;
	len=0; res=0; top=0;
	for(i=0;i<=n;i++){
		for(j=i+1;j<=n;j++){
			v=1ll*(x[i]-x[j])*(x[i]-x[j])+1ll*(y[i]-y[j])*(y[i]-y[j]);
			len++;
			p[len].w=v;
			p[len].x=i; p[len].y=j;
			len++;
			p[len].w=v;
			p[len].x=j; p[len].y=i;
		}
	}
	sort(p+1,p+1+len,cmp);
	for(i=1;i<=len;i=j+1){
		j=i;
		while((j<len)&&(p[j+1].w==p[j].w)){
			++j;
		}
		top=0;
		for(;i<=j;i++){
			if(p[i].y){
				tp[++top]=p[i].y;
				V[top]=dp[p[i].x];
			}
		}	
		while(top){
			dp[tp[top]]=max(dp[tp[top]],V[top]+1);
			--top;
		}
	}
	for(i=0;i<=n;i++){
		res=max(res,dp[i]);
	}
	cout<<res<<"\n";
}
### 2024 暑期训练营 Sort4 题目解析 #### 题目背景与描述 在2024年的暑期训练营中,Sort4是一道涉及字符串排序和字典序比较的题目。该题目的核心在于通过特定的操作改变给定字符串数组的顺序,并最终使得整个序列达到某种最优状态。 #### 解决方案概述 为了有效解决这个问题,需要理解并应用分治算法以及RMQ(Range Minimum Query)技术来优化查询效率[^3]。具体来说: - **初始化阶段**:读入输入数据并将所有字符串存储在一个列表中。 - **预处理部分**:构建笛卡尔树用于快速查找最小值及其位置;同时记录每个节点的信息以便后续更新操作时能够高效定位目标元素的位置。 - 对于每一次交换请求\( (d_i, p_i) \),判断当前待调整项是否满足条件 \( d_i > p_i \)。如果是,则执行相应的移动动作使新的排列更接近理想解; - 使用自定义比较器对修改后的集合重新排序,确保整体结构仍然保持有序特性不变; - 继续上述过程直至完成全部指令集中的每一条命令为止。 ```cpp #include <bits/stdc++.h> using namespace std; struct Node { int val; int idx; }; bool cmp(Node a, Node b){ return a.val < b.val || (a.val == b.val && a.idx < b.idx); } vector<Node> nodes; int n, q; void buildCartesianTree() {/* ... */ } // 执行单步转换操作 void performOperation(int di, int pi) { if(di > pi){ // 当di大于pi时才会引起字典序变化 swap(nodes[di],nodes[pi]); sort(nodes.begin(), nodes.end(),cmp); } } ``` 此段代码展示了如何基于给定条件实施一次有效的变换,并维持全局秩序不受影响。需要注意的是,在实际竞赛环境中可能还需要额外考虑边界情况以及其他潜在陷阱。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值