zoukankan      html  css  js  c++  java
  • CF433C 【Ryouko's Memory Note】

    题意:

    给出2个正整数 (n,m(1le n,m le 10^5)) ,接下去给出 (a_1,a_2,cdots a_m(1le a_ile n))

    你可以把这个序列里所有值为 (a_i) 的元素改成 (a_j) ((1le i,jle m)) ,注意 (i) 可以等于 (j) ,只可以改一次。

    最小化 (sumlimits_{i=1}^{ile m-1} |a_i-a_{i+1}|)

    (Solution)

    有个性质:有一个数列 (a_1,a_2,cdots a_n) ,取一个元素 (a_x) ,最小化 (sumlimits_{i=1}^{ile n} |a_x-a_{i}|) ,则 (a_x) 为这个数列的中位数。

    可以 (O(n)) 预处理出所有与它相邻的数,并且知道一次都不换(或者 i=j的时候的结果)

    假设我们已经知道了要替换哪个值,先O(相邻数的个数)跑一遍统计最初的贡献,接着应用上面那个性质,可以知道应该把这个数替换成与它相邻数的序列的中位数,再 O(相邻数的个数) 跑一遍统计现在的贡献,2次贡献作差即为把这个数换掉最多能减小多少。这样跑一次是 O(相邻数的个数*log(相邻数的个数)) 的(因为排序找中位数,带个log)

    但是我们并不知道该替换哪个,可是发现被替换的数的值域在枚举的范围内,直接枚举即可。

    总的复杂度:(O(mlog m)) ,可以通过。因为相邻数的个数总共 (2m) 个,排序带个log,枚举 (n) 可以忽略不计。

    #include <bits/stdc++.h>
    using namespace std;
    #define rint register int
    const int N=100010;
    int n,m,a[N];
    long long ans,s;
    vector<int>v[N];
    int main() {
    	scanf("%d%d",&n,&m);
    	for(rint i=1;i<=m;++i)scanf("%d",&a[i]);
    	for(rint i=1;i<m;++i) {
    		s+=abs(a[i]-a[i+1]);
    		if(a[i]!=a[i+1]) {
    			v[a[i]].push_back(a[i+1]);
    			v[a[i+1]].push_back(a[i]);
    		}
    	}
    	ans=s;
    	long long sum,lst;
    	for(rint i=1;i<=n;++i) {
    		if(!v[i].size())continue;
    		sum=lst=0;
    		for(rint j=0;j<v[i].size();++j)
    			lst+=abs(i-v[i][j]);
    		sort(v[i].begin(),v[i].end());
    		int mid=v[i].size()/2;
    		for(rint j=0;j<v[i].size();++j)
    			sum+=abs(v[i][mid]-v[i][j]);
    		ans=min(ans,s-lst+sum);
    	}
    	printf("%lld
    ",ans);
    	return 0;
    }
    

    PS:中位数有个 nth_element 函数,均摊线性,用法可以问百度 ,所以本题其实可以均摊 (O(m)) ,只需要把循环改成这样:

    	for(rint i=1;i<=n;++i) {
    		if(!v[i].size())continue;
    		sum=lst=0;
    		for(rint j=0;j<v[i].size();++j)
    			lst+=abs(i-v[i][j]);
    		int mid=v[i].size()/2;
    		nth_element(v[i].begin(),v[i].begin()+mid,v[i].end());
    		for(rint j=0;j<v[i].size();++j)
    			sum+=abs(v[i][mid]-v[i][j]);
    		ans=min(ans,s-lst+sum);
    	}
    

    第一次提交的时候代码放错了,请管理员通过一下第2次的,谢谢

    upd:发现公式写错了一个地方,已经更改,麻烦管理员了,谢谢!

    路漫漫其修远兮,吾将上下而求索
  • 相关阅读:
    [LeetCode]Set Matrix Zeroes
    计算4000000000内的最大f(n)=n值---字符串的问题python实现(五岁以下儿童)
    ajax提交与上传文件同步
    清理收缩VMware虚拟机MacOS系统的vmdk文件大小
    Codeforces Round #243 (Div. 1)-A,B,C-D
    oracle substr功能
    DP 水的问题
    [LeetCode]Evaluate Reverse Polish Notation
    2014鞍山直播比赛H称号HDU5077(DFS修剪+通过计)
    Android
  • 原文地址:https://www.cnblogs.com/zzctommy/p/12918531.html
Copyright © 2011-2022 走看看