Codeforces Round #248 (Div. 2) C - Ryouko's Memory Note


に言及
1冊の本にはnページある.次はm個の知識点を探して、それぞれs[1]s[2]....s[m]ページにあります.あるページの知識点をすべて別のページに移動する機会があります.最も少ないページをめくる回数を求めます.
例えばs[1]s[2]....s[m]のページめくり回数は|s[1]-s[2]|+|s[2]-s[3]|+...+|s[m-1]-s[m]|
構想
各ページ番号がシーケンスの前後に現れるページ番号(例えば1 2 3 2 4では2前後に1 3 3 4が現れたことがある)を記録し(隣接するページ番号が同じであれば構わないことに注意)、それらの中位数を取ると、必ずこのページ番号を移動する最適解がある.すべてのページ番号を一度遍歴して、全体の最適解を取ればいいです.
コード#コード#
#include 
#include 
#include 
#include 
#include 
#include 
#define ll long long
using namespace std;
const int maxn = 100010;
const ll INF = 1e10L;
int s[maxn];
vector<int> ss[maxn];
ll close[maxn];
ll closee[maxn];
ll sum;
ll ans;
int ma;
int n,m;
int main()
{
    scanf("%d%d",&n,&m);
    for(int i = 1 ; i <= m ; i ++) {
        scanf("%d",&s[i]);
        ma = max(ma,s[i]);
        if(i != 1) {
            sum += abs(s[i]-s[i-1]);
            if(s[i] == s[i-1]) continue;
            ss[s[i]].push_back(s[i-1]);
            ss[s[i-1]].push_back(s[i]);
            close[s[i]] += abs(s[i]-s[i-1]);
            close[s[i-1]] += abs(s[i]-s[i-1]);
        }
    }
    ans = sum;
    for(int i = 1 ; i <= ma ; i ++) {
        if(!ss[i].size()) continue;
        sort(ss[i].begin(),ss[i].end());
        int mid = ss[i].size()/2;
        for(int j = 0 ; j < ss[i].size() ; j ++) {
            closee[i] += abs(ss[i][j]-ss[i][mid]);
        }
        ans = min(ans,sum-close[i]+closee[i]);
    }
    cout << ans << endl;
    return 0;
}