Ryouko's Memory Note(书本翻页)

题目大意:

首先输入两个数:n,m。n表示记事本有n页(1~n编号),m表示Ryouko需要的资料在m个页码上(页码可以重复),现在允许Ryouko将一页上的内容搬到另一页上,要求搬完之后使得Ryouko的翻页次数最小。输出最小的翻页次数。

m个页码值分别为a[1]、a[2]、...、a[m],Ryouko总共的翻页次数为

解题思路:

使用容器保存需要翻页的页码之前和之后的页码编号,如果之前或之后的页码和编号和当前的页码编号是一样的,则不需要加入容器中,对于每一个页面编码,都会有一个邻近编号容器adj[i][j], adjSum[i] 是对于当前页码的邻近数组中翻到当前页面的次数之和,sum为总的翻页次数(搬页之前),adjMinSum[i]是对于当前编号,在邻近表中选个中位数后各个邻近页码编号到中位数的距离。最终结果是sum-adjSum[i]+adjMinSum[i] 的最小值。

例如:

4   6

1  2  3  4  3  2


代码:

#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
#define M 100005
#define LL long long
using namespace std;

int a[M];           //页码编号
LL adjSum[M];       
LL adjMinSum[M];
vector<int> adj[M];
LL min(LL a, LL b){
    if(a < b) return a;
    return b;
}
int main(){
    int n, m;
    LL sum, ans;
    while(~scanf("%d%d", &n, &m)){
        for(int i=1; i<=m; i++){
            scanf("%d", a+i);
        }
        for(int i=1; i<=m; i++){
            if(i != 1 && a[i] != a[i-1]) adj[a[i]].push_back(a[i-1]);
            if(i != m && a[i] != a[i+1]) adj[a[i]].push_back(a[i+1]);
        }
        memset(adjSum, 0 ,sizeof(adjSum));
        sum = 0;
        for(int i=1; i<=n; i++){
            if(adj[i].size()){
                for(int j=0; j<adj[i].size(); j++){
                    adjSum[i] += (i > adj[i][j] ? i-adj[i][j] : adj[i][j]-i);

                }
                sum += adjSum[i];
            }
        }
        sum /= 2;
        ans = sum;
        memset(adjMinSum, 0, sizeof(adjMinSum));
        for(int i=1; i<=n; i++){
            sort(adj[i].begin(), adj[i].end());
        }
        for(int i=1; i<=n; i++){
            int mid = adj[i].size()/2;
            for(int j=0; j<adj[i].size(); j++){
                adjMinSum[i] += (adj[i][mid] > adj[i][j] ? adj[i][mid]-adj[i][j] : adj[i][j]-adj[i][mid]);
            }
            ans = min(ans, sum - adjSum[i] + adjMinSum[i]);
        }
        printf("%lld\n", ans);
        for(int i=1; i<=n; i++){
            adj[i].clear();
        }
    }
    return 0;
}

注意:

1、数据类型要用到long long 型,不然在计算过程中会出现溢出。

2、容器用完之后要进行clear()操作

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值