At338 D - Island Tour
D.Island Tour
题意概述
给定一个长度为n的(\(n\geq 3\))序列,\(a_i与a_{i+1}之间连一条边(i < n)\),\(a_n与a_1之间连一条边\),每条边的长度是1,现给定长为m的点集合序列b,求可以任意删除一条边的情况下按照b的移动顺序经过的总路程S。
解题思路
注意到,序列有以下几个性质
1.没有删除边前,序列元素形成一个环。
2.没有删除边前,每次从\(b_i 到 b_{i+1}\)有两种代价的方式,
一种是直接从小边走向大边,消耗\(s1=|b_i-b_{i+1}|\)的代价,
另一种是小边绕一圈,消耗\(s2=|n-(b_i-b_{i+1})|\)的代价。
3.删除边后,每个点走向另一个点只有一种方案,相当于每次走边在没有删边的基础上多消耗了\(|s1-s2|\)的代价。
4.那么我们要解决的问题就转化到了\(总代价=删边前总代价和+加上删边后多的代价之和\)
删边前的总代价直接对两种走边方式取最大值即可,删边后多走的代价可以使用差分数组和前缀和还原的思想统计
AC code
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
typedef long long ll;
const ll inf=1e18;
int main(){
cin.tie(0)->ios::sync_with_stdio(false);
int n,m;cin>>n>>m;
vector<int>a(m+1);
vector<ll>d(n+2);
ll ans=0;
for(int i=1;i<=m;i++) cin>>a[i];
for(int i=1;i<m;i++){
int u=a[i],v=a[i+1];
if(u>v) swap(u,v);
ll rt1=v-u,rt2=n-rt1;
if(rt1<rt2){
d[u]+=rt2-rt1,
d[v]-=rt2-rt1;
}
else{
d[v]+=rt1-rt2;
d[u]-=rt1-rt2;
d[1]+=rt1-rt2;
}
ans+=min(rt1,rt2);
}
for(int i=1;i<=n;i++) d[i]+=d[i-1];
cout<<ans+*min_element(d.begin()+1,d.begin()+1+n)<<endl;
return 0;
}