• 笔记


    【问题描述】

    给定一个长度为m的序列a,下标编号为1~m。序列的每个元素都是1~n的

    整数。定义序列的代价为Σa[i+1]-a[i]

    你现在可以选择两个数x和y,并将序列a中所有的x改成y。x可以与y相等。

    请求出序列最小可能的代价。

    【输入格式】

    输入第一行包含两个整数n和m。第二行包含m个空格分隔的整数,代表序列a。

    【输出格式】

    输出一行,包含一个整数,代表序列最小的代价。

    【样例输入 1】

    4 6

    1 2 3 4 3 2

    【样例输出 1】

    3

    【样例输入 2】

    10 5

    9 4 3 8 8

    【样例输出 1】

    6

    【样例解释】

    样例 1 中,最优策略为将 4 改成 3。样例 2 中,最优策略为将 9 改成 4。

    【数据规模和约定】

    60%的数据,n,m ≤ 2000。

    对于100%的数据,1 ≤ n,m ≤ 100,000。

    /*
      这道题告诉我们,初中数学没学好是多么可怕的一件事~
      我们统计每个与i相邻的数grap[i],然后尽量使 Σ|grap[i]-i| 最小,那么我们就使i变成grap[i]的中位数(貌似结论很显然,然而我写的是平均数),然后对于每个i,去它们对答案贡献的最大值。 
    */
    #include<cstdio>
    #include<iostream>
    #include<vector>
    #include<algorithm>
    #define N 100010
    #define lon long long
    using namespace std;
    int a[N],m,n;
    vector<int> grap[N];
    int main(){
        freopen("note.in","r",stdin);
        freopen("note.out","w",stdout);
        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])grap[a[i-1]].push_back(a[i]);
            if(i<m&&a[i]!=a[i+1])grap[a[i+1]].push_back(a[i]);
        }
        lon ans=0LL,sum=0LL;
        for(int i=1;i<=n;i++){
            if(!grap[i].size())continue;
            sort(grap[i].begin(),grap[i].end());
            int z=grap[i][grap[i].size()>>1];
            lon qian=0LL,hou=0LL;
            for(int j=0;j<grap[i].size();j++){
                qian+=(lon)(abs(i-grap[i][j]));
                hou+=(lon)(abs(z-grap[i][j]));
            }
            ans=max(ans,qian-hou);sum+=qian;
        }
        cout<<sum/2-ans;
        return 0;
    }
  • 相关阅读:
    水波模拟算法
    火车调度问题
    讨论范式
    字符串编码传输
    意识的物质,物质的意识
    需求分析——项目日志管理系统
    委托揭秘
    [9]OCP:开放封闭原则
    NULL OBJECT 模式
    由《通用权限设计》而引发的随想
  • 原文地址:https://www.cnblogs.com/harden/p/6059936.html
Copyright © 2020-2023  润新知