其他分享
首页 > 其他分享> > 【洛谷P6563】一直在你身旁

【洛谷P6563】一直在你身旁

作者:互联网

题目

题目链接:https://www.luogu.com.cn/problem/P6563
回到这座小镇后,她的新工作是维修电线。
现在,有一根电线坏了。已知电线长度可能为 \(1\),\(2\),...,\(n\) 中的一个数。现在,她需要知道电线的长度。
她可以花费 \(a_i\) 块钱购买长度为 \(i\) 的电线。购买这根电线后,她能知道所需要的电线长度是否 大于 \(i\)。
保证 \(a_1 \le a_2 \le \cdots \le a_n \le 10^9\)。
问她至少要花多少钱才能保证知道需要电线的长度。
\(Q\leq 500,\sum n\leq 7100\)。

思路

容易想到设 \(f[i][j]\) 表示电线长度在区间 \([i,j]\) 时,至少需要多少钱才能知道电线的长度。
有转移

\[f[i][j]=\min_{k\in [i,j)}(\max(f[i][k],f[k+1][j])+a_k) \]

时间复杂度 \(O(n^3)\)。
我们发现转移中有一个 \(\max\) 并不好处理,所以考虑分类把 \(\max\) 拆开。
对于一个区间 \([i,j]\),我们设 \(k\) 表示满足 \(f[i][k]>f[k+1][j]\) 的最小的位置。不难当 \(i\) 不变时 \(k\) 是单调不减的。所以可以在枚举区间的时候顺便求出。
考虑转移点的位置 \(l\):

时间复杂度 \(O(n^2)\)。

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const int N=7110;
int Q,n,a[N];
ll f[N][N];
deque<int> q;

int main()
{
	scanf("%d",&Q);
	while (Q--)
	{
		scanf("%d",&n);
		for (int i=1;i<=n;i++)
			scanf("%d",&a[i]);
		for (int j=1;j<=n;j++)
		{
			while (q.size()) q.pop_back();
			for (int i=j-1,k=j-1;i>=1;i--)
			{
				while (q.size() && f[i+1][j]+a[i]<=f[q.back()+1][j]+a[q.back()]) q.pop_back();
				q.push_back(i);
				while (k>i && f[i][k-1]>f[k][j]) k--;
				f[i][j]=f[i][k]+a[k];
				while (q.size() && q.front()>=k) q.pop_front();
				if (q.size()) f[i][j]=min(f[i][j],f[q.front()+1][j]+a[q.front()]);
			}
		}
		printf("%lld\n",f[1][n]);
	}
	return 0;
}

标签:身旁,le,洛谷,int,电线,--,front,长度,P6563
来源: https://www.cnblogs.com/stoorz/p/14729524.html