[ABC201F] Insertion Sort

一、题目

点此看题

\(n\) 个人,编号从 \(1\)\(n\),一开始位置 \(i\) 上站着人 \(p_i\),有这三种操作,问将人从小到大排序的最小花费:

  • 支付 \(a_i\),可以让第 \(i\) 个人移动到任意的位置。
  • 支付 \(b_i\),可以让第 \(i\) 个人移动到最左边的位置。
  • 支付 \(c_i\),可以让第 \(i\) 个人移动到最右边的位置。

\(1\leq n\leq 2\cdot 10^5,1\leq p_i\leq n,1\leq a_i,b_i,c_i\leq 10^9\)

二、解法

最后是把所有人从小到大排,可以思考怎么样把每个人换到该换的地方去。显然每个人最多换一次,那么每个人就有四种状态:不换;换任意位置;换到最左边位置;换到最右边位置。

这就是一个确定状态的问题,我们先考虑暴力,再考虑优化。要想一想有没有比枚举每个点的四种状态更好的做法,我们可以枚举集合 \(S=(s_1,s_2...s_k)\)\(s_i\) 表示 \(s_i\) 这个人不会动,那么对于剩下的人能很自然地确定他们的状态:

  • \(1\leq x<s_1\),这些人就支付 \(\min(a_x,b_x)\) 换到最终的位置。
  • \(s_i< x<s_{i+1}\),这些人就支付 \(a_x\) 换到最终的位置(使用 \(2,3\) 操作一定会越过不能动的点)
  • \(s_{k}<x\leq n\),这些人就支付 \(\min(a_x,c_x)\) 换到最终的位置。

不难发现 \(s_1<s_2<...<s_k\),这变成了在 \([1,n]\) 这个线段上的规划问题,设 \(dp[i]\) 为将第 \(i\) 个人规定不动的最小花费,那么我们枚举上一个规定不动的人 \(j\) 或者直接把他作为第一个人:

\[dp[i]=\min(\sum_{k=1}^{i-1}\min(a_k,b_k),dp[j]+\sum_{k=i+1}^{j-1}a_k) \]

最后的答案是 \(\min dp[i]+\sum_{k=i+1}^n\min(a_k,c_k)\),全部人都换的情况一定不是最优的。

显然我们可以用线段树优化做到 \(O(n\log n)\)

#include <cstdio>
#include <iostream>
using namespace std;
#define int long long
const int M = 200005;
const int inf = 1e18;
int read()
{
	int x=0,f=1;char c;
	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
	return x*f;
}
int n,ans,p[M],a[M],b[M],c[M],A[M],B[M],C[M],dp[M],bit[M];
int lowbit(int x)
{
	return x&(-x);
}
void add(int x,int y)
{
	for(int i=x;i<=n;i+=lowbit(i))
		bit[i]=min(bit[i],y);
}
int ask(int x)
{
	int r=inf;
	for(int i=x;i>0;i-=lowbit(i))
		r=min(r,bit[i]);
	return r;
}
signed main()
{
	n=read();ans=inf;
	for(int i=1;i<=n;i++)
	{
		int x=read();
		p[x]=i;//the position of person x
		bit[i]=inf;
	}
	for(int i=1;i<=n;i++)
	{
		a[i]=read(),b[i]=read(),c[i]=read();
		A[i]=A[i-1]+a[i];
		B[i]=B[i-1]+min(a[i],b[i]);
		C[i]=C[i-1]+min(a[i],c[i]);
	}
	for(int i=1;i<=n;i++)
	{
		dp[i]=min(B[i-1],ask(p[i])+A[i-1]);
		add(p[i],dp[i]-A[i]);
		ans=min(ans,dp[i]+C[n]-C[i]);
	}
	printf("%lld\n",ans);
}
posted @ 2021-05-18 21:20  C202044zxy  阅读(301)  评论(1编辑  收藏  举报