[CF704B] Ant Man
\(\text{Problem}:\)Ant Man
\(\text{Solution}:\)
首先容易考虑一个建图跑最短路的做法。但这显然就假了,原因是:无法保证路径长度;无法保证每个点至多被遍历一次。
但这提示我们如果存在一个能保证路径长度的做法,可能就可以解决本题。考虑初始状态只有 \(s,e\) 两个点。如果存在一种更新方式,使得每次插入一个全新的点都能保证局部最优,那么就解决了一开始做法的问题。
不难发现,若当前序列是 \(s,p_{1},p_{2},\cdot\cdot\cdot,p_{k},e\),则只要找到最优的位置插入 \(p_{k+1}\) 即可。而这一定全局最优,利用反证法即可证明。时间复杂度 \(O(n^2)\)。
\(\text{Code}:\)
#include <bits/stdc++.h>
//#pragma GCC optimize(3)
#define int long long
#define ri register
#define mk make_pair
#define fi first
#define se second
#define pb push_back
#define eb emplace_back
#define is insert
#define es erase
#define vi vector<int>
#define vpi vector<pair<int,int>>
using namespace std; const int N=5010;
inline int read()
{
int s=0, w=1; ri char ch=getchar();
while(ch<'0'||ch>'9') { if(ch=='-') w=-1; ch=getchar(); }
while(ch>='0'&&ch<='9') s=(s<<3)+(s<<1)+(ch^48), ch=getchar();
return s*w;
}
int n,S,E,ans,pre[N],nxt[N];
struct Node { int x,a,b,c,d; }q[N];
inline int Go(int i,int j)
{
if(i>j) return q[i].x-q[j].x+q[i].c+q[j].b;
return q[j].x-q[i].x+q[i].d+q[j].a;
}
signed main()
{
n=read(), S=read(), E=read();
for(ri int i=1;i<=n;i++) q[i].x=read();
for(ri int i=1;i<=n;i++) q[i].a=read();
for(ri int i=1;i<=n;i++) q[i].b=read();
for(ri int i=1;i<=n;i++) q[i].c=read();
for(ri int i=1;i<=n;i++) q[i].d=read();
pre[E]=S, nxt[S]=E;
ans=Go(S,E);
for(ri int i=1;i<=n;i++)
{
if(i==S||i==E) continue;
int pos=0, mi=1e18;
int x=S;
while(nxt[x])
{
int v=nxt[x];
int w=Go(x,i)+Go(i,v)-Go(x,v);
if(mi>w) pos=x, mi=w;
x=nxt[x];
}
ans+=mi;
pre[i]=pos, nxt[i]=nxt[pos];
pre[nxt[pos]]=i, nxt[pos]=i;
}
int x=S;
printf("%lld\n",ans);
return 0;
}
夜畔流离回,暗叹永无殿。
独隐万花翠,空寂亦难迁。
千秋孰能为,明灭常久见。
但得心未碎,踏遍九重天。