【题解】CF704B Ant Man

发布时间 2023-08-07 20:02:00作者: xishanmeigao

题目传送门

一道很好的排列 \(\rm dp\)(连续段 \(\rm dp\))的题目。

我们考虑从小到大插入这 \(n\) 个数,设 \(f[i][j]\) 表示现在考虑到第 \(i\) 个数,有 \(j\) 个连续段的最小权值,初始化为正无穷。

那么我们在插入一个数 \(i\) 时,要将 \(i\) 可能会产生的贡献提前计算。注意到如果 \(i=s\)\(i=e\) 时贡献会有所不同,所以我们要分情况讨论:

  • \(i=s\)

    • \(i\) 插入到第一个连续段的最前面:

      \(f[i-1][j]+x_i+c_i\rightarrow f[i][j]\)

    • \(i\) 放在最前面自成一段,注意此时若 \(e\) 已经插入,则要求 \(j\geq 1\)

      \(f[i-1][j]-x_i+d_i\rightarrow f[i][j+1]\)

  • \(i=e\)

    • \(i\) 插入到最后一个连续段的最后面:

      \(f[i-1][j]+x_i+a_i\rightarrow f[i][j]\)

    • \(i\) 放到最后面自成一段,注意此时若 \(s\) 已经插入,则要求 \(j\geq 1\)

      \(f[i-1][j]-x_i+b_i\rightarrow f[i][j+1]\)

  • \(i\ne s\)\(i\ne e\)

    • \(i\) 插入到左边,注意若 \(s\) 已经插入,则要求 \(j>1\)

      \(f[i-1][j]+b_i+c_i\rightarrow f[i][j]\)

    • \(i\) 插入到右边,注意若 \(e\) 已经插入,则要求 \(j>1\)

      \(f[i-1][j]+a_i+d_i\rightarrow f[i][j]\)

    • \(i\) 合并两个连续段,此时要求 \(j\geq 2\)

      \(f[i-1][j]+x_i+x_i+a_i+c_i\rightarrow f[i][j-1]\)

    • \(i\) 自成一段,注意若 \(s\)\(e\) 若已经插入则对 \(j\) 有要求:
      \(f[i-1][j]-x_i-x_i+b_i+d_i\rightarrow f[i][j+1]\)

最后输出 \(f[n][1]\),那这道题就愉快地结束了!

#include<bits/stdc++.h>
#define LL long long
using namespace std;

const int N=5010;

int n,s,e;
LL f[N][N];
int x[N],a[N],b[N],c[N],d[N];

int main()
{
	memset(f,0x3f,sizeof(f));
	
	scanf("%d%d%d",&n,&s,&e);
	for(int i=1; i<=n; i++)
		scanf("%d",&x[i]);
	for(int i=1; i<=n; i++)
		scanf("%d",&a[i]);
	for(int i=1; i<=n; i++)
		scanf("%d",&b[i]);
	for(int i=1; i<=n; i++)
		scanf("%d",&c[i]);
	for(int i=1; i<=n; i++)
		scanf("%d",&d[i]);
		
	f[0][0]=0;
	for(int i=1; i<=n; i++)
	{
		for(int j=0; j<i; j++)
		{
			if(i==s)
			{
				f[i][j]=min(f[i][j],f[i-1][j]+x[i]+c[i]);
				if(j>=(i>e))
					f[i][j+1]=min(f[i][j+1],f[i-1][j]-x[i]+d[i]);
			}
			else if(i==e)
			{
				f[i][j]=min(f[i][j],f[i-1][j]+x[i]+a[i]);
				if(j>=(i>s))
					f[i][j+1]=min(f[i][j+1],f[i-1][j]-x[i]+b[i]);
			}
			else
			{
				if(j>1 || (i<s && j>0))
					f[i][j]=min(f[i][j],f[i-1][j]+b[i]+c[i]);
				if(j>1 || (i<e && j>0))
					f[i][j]=min(f[i][j],f[i-1][j]+a[i]+d[i]);
				if(j>=2)
					f[i][j-1]=min(f[i][j-1],f[i-1][j]+x[i]+x[i]+a[i]+c[i]);
				if(j>=((i>s)+(i>e)))
					f[i][j+1]=min(f[i][j+1],f[i-1][j]-x[i]-x[i]+b[i]+d[i]);
			}
		}
	}
	
	printf("%lld",f[n][1]);
	
	return 0;
}