题意
一本书有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 <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
#include <iostream>
#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;
}
Codeforces Round #248 (Div. 2) C - Ryouko's Memory Note
时间: 2024-10-10 23:31:09