题目链接
https://arc073.contest.atcoder.jp/tasks/arc073_d
题意简述
有 n n n个格子,有两颗棋子,初始位置为 A , B A,B A,B,移动一颗棋子从 X X X到 Y Y Y的代价是 ∣ X − Y ∣ |X-Y| ∣X−Y∣,有 Q Q Q个要求,每个要求是将任意一颗棋子移动到 X i X_i Xi点,求代价最小值。
题解
设
f
[
i
]
[
j
]
f[i][j]
f[i][j]表示前
i
i
i个要求被满足,一颗棋子在
X
i
X_i
Xi,另一颗在
j
j
j花费的最小代价,转移
f
[
i
]
[
j
]
=
f
[
i
−
1
]
[
j
]
+
∣
X
i
−
X
i
−
1
∣
f
[
i
]
[
X
i
−
1
]
=
min
k
=
1
n
(
f
[
i
−
1
]
[
k
]
+
∣
k
−
X
i
∣
)
f[i][j]=f[i-1][j]+|X_i-X_{i-1}|\\ f[i][X_{i-1}]=\min_{k=1}^{n} (f[i-1][k]+|k-X_i|)
f[i][j]=f[i−1][j]+∣Xi−Xi−1∣f[i][Xi−1]=k=1minn(f[i−1][k]+∣k−Xi∣)
发现第一维可以省掉,用线段树维护第二维,维护三个值
(
f
[
i
]
+
i
)
,
(
f
[
i
]
+
n
−
i
+
1
)
,
f
[
i
]
(f[i]+i),(f[i]+n-i+1),f[i]
(f[i]+i),(f[i]+n−i+1),f[i],第一种转移就是区间加,第二种就只要对
X
i
−
1
X_{i-1}
Xi−1右侧的
(
f
[
i
]
+
i
)
−
X
i
(f[i]+i)-X_i
(f[i]+i)−Xi,左侧的
(
f
[
i
]
+
n
−
i
+
1
)
−
n
+
X
i
−
1
(f[i]+n-i+1)-n+X_i-1
(f[i]+n−i+1)−n+Xi−1取
min
\min
min,然后区间修改就行了。
代码
#include <cstdio>
#include <algorithm>
int read()
{
int x=0,f=1;
char ch=getchar();
while((ch<'0')||(ch>'9'))
{
if(ch=='-')
{
f=-f;
}
ch=getchar();
}
while((ch>='0')&&(ch<='9'))
{
x=x*10+ch-'0';
ch=getchar();
}
return x*f;
}
const int maxn=200000;
const long long inf=0x3f3f3f3f3f3f3f3fll;
int n,q,sta,stb,a[maxn+10];
namespace sgt
{
long long mn[3][maxn<<2],adt[maxn<<2];
int puttag(int x,long long v)
{
mn[0][x]+=v;
mn[1][x]+=v;
mn[2][x]+=v;
adt[x]+=v;
return 0;
}
int pushdown(int x)
{
puttag(x<<1,adt[x]);
puttag(x<<1|1,adt[x]);
adt[x]=0;
return 0;
}
int updata(int x)
{
mn[0][x]=std::min(mn[0][x<<1],mn[0][x<<1|1]);
mn[1][x]=std::min(mn[1][x<<1],mn[1][x<<1|1]);
mn[2][x]=std::min(mn[2][x<<1],mn[2][x<<1|1]);
return 0;
}
int build(int x,int l,int r)
{
if(l==r)
{
mn[0][x]=inf+l;
mn[1][x]=inf+n-l+1;
mn[2][x]=inf;
return 0;
}
int mid=(l+r)>>1;
build(x<<1,l,mid);
build(x<<1|1,mid+1,r);
updata(x);
return 0;
}
int add(int x,int l,int r,int askl,int askr,long long adv)
{
if((askl<=l)&&(r<=askr))
{
puttag(x,adv);
return 0;
}
int mid=(l+r)>>1;
pushdown(x);
if(askl<=mid)
{
add(x<<1,l,mid,askl,askr,adv);
}
if(mid<askr)
{
add(x<<1|1,mid+1,r,askl,askr,adv);
}
updata(x);
return 0;
}
long long getmn(int x,int l,int r,int askl,int askr,int id)
{
if((askl<=l)&&(r<=askr))
{
return mn[id][x];
}
int mid=(l+r)>>1;
long long res=inf<<1;
pushdown(x);
if(askl<=mid)
{
res=std::min(res,getmn(x<<1,l,mid,askl,askr,id));
}
if(mid<askr)
{
res=std::min(res,getmn(x<<1|1,mid+1,r,askl,askr,id));
}
return res;
}
}
int abs(int x)
{
return (x<0)?(-x):x;
}
int main()
{
n=read();
q=read();
sta=read();
stb=read();
for(int i=1; i<=q; ++i)
{
a[i]=read();
}
a[0]=sta;
sgt::build(1,1,n);
sgt::add(1,1,n,stb,stb,-inf);
for(int i=1; i<=q; ++i)
{
long long oth=std::min(sgt::getmn(1,1,n,1,a[i],1)-(n-a[i]+1),sgt::getmn(1,1,n,a[i],n,0)-a[i]);
sgt::add(1,1,n,1,n,abs(a[i]-a[i-1]));
long long nth=sgt::getmn(1,1,n,a[i-1],a[i-1],2);
if(nth>oth)
{
sgt::add(1,1,n,a[i-1],a[i-1],oth-nth);
}
}
printf("%lld\n",sgt::getmn(1,1,n,1,n,2));
return 0;
}