题目描述

小C有一个N个数的整数序列,这个序列的中的数两两不同。小C每次可以交换序列中的任意两个数,代价为这两个数之和。小C希望将整个序列升序排序,问小C需要的最小代价是多少?

输入输出格式

输入格式:

第一行,一个整数N。

第二行,N个整数,表示小C的序列。

输出格式:

一行,一个整数,表示小C需要的最小代价。

输入输出样例

输入样例#1:

6
8 4 5 3 2 7
输出样例#1:

34

说明

数据范围:

对于30%的数据,1<=N<=10;

对于全部的数据,1<=N<=100000,输入数据中的其他整数均为正整数且不超过$10^9$。

Solution:

  本题貌似说是什么群论(可惜至少我现在不会,挖坑拉~手动滑稽~)。但是实际上,一点简单的思维(类似贪心)就可以做出来。

  首先我们假设原数列为数组$a$,目标数列为数组$b$($b$为$a$从小到大排序后的数组)。

  对比$a_i,b_i$,则我们容易发现,相互之间需要交换位置的数会出现在同一集合中(举样例:$8\;4\;5\;3\;2\;7$排序后为$2\;3\;4\;5\;7\;8$,此时整个数列分为了$2$个集合:$\begin{Bmatrix} 2\;7\;8\end{Bmatrix}$和$\begin{Bmatrix} 3\;4\;5\end{Bmatrix}$)。

  容易发现:当某一集合元素大于$size\geq 1$时,该集合内的数一定位置互异,且只需以其中$1$个数去和该集合中其他的$size-1$个数各交换一次,就能使得该集合元素大小和位置对应(可以用样例试试,我这里不模拟了)。

  再由题意中交换一次的代价的定义,很容易贪心想到:

  1、若只用同一集合中的元素交换,那么使得某一集合中的元素大小和位置对应需要的代价最小应该是用该集合中的最小元素$minn$去和其它元素交换,此时不妨假设某一集合$p$有$k$个元素,这$k$个元素之和为$sum$,设$p$中最小的元素为$p_1$,那么交换代价$cost=(p_1+p_2)+(p_1+p_3)+(p_1+p_4)+…+(p_1+p_{k-1})$,化简得$cost=(k-1)*p_1+sum-p_1=(k-2)*p_1+sum$。可以证明当该交换集合中的最小元素$p_1$同时是全集(即原数列$a$)中的最小值时,上述方法所求的$cost$即为该集合的最小代价。

  2、但是当$p$集合中的最小值不是$a$中最小值时,只用同一集合中的元素去交换不一定最优,因为我们可以将全集$a$中的最小值加入$p$集合可能会使$cost$更小(举例:原序列$a:\;1\;15\;11\;13\;14$,若按直接按上面的方法则花费为$75$,但实际上我们将$1$先和$11$进行一次交换代价为$1+11$,这样$1$就以当前最小的代价$12$加进了该交换集合,此时再去算答案为$69$)。由上面的例子容易想到,我们以最小的代价即将$minn$与$p_1$交换,此时$minn$加进了交换集合,则交换代价$cost=minn+p_1+(minn+p_1)+(minn+p_2)+…+(minn+p_k)=minn*(k+1)+tot+p_1$。此时比较一下两种情况,取最小代价。

  实现时,就按上述步骤,求交换集合,比较$ans$本题就$ok$了。

代码:

#include<bits/stdc++.h>
#define il inline
#define ll long long
#define inf 233333333333333
using namespace std;
const int N=;
il ll gi(){
ll a=;char x=getchar();bool f=;
while((x<''||x>'')&&x!='-')x=getchar();
if(x=='-')x=getchar(),f=;
while(x>=''&&x<='')a=a*+x-,x=getchar();
return f?-a:a;
}
ll n,ans,b[N],minn=inf;
struct point{
ll v,id;
bool operator <(point a){return v<a.v;}
}a[N];
bool vis[N];
int main()
{
n=gi();
for(int i=;i<=n;i++)a[i].v=gi(),a[i].id=i,b[i]=a[i].v,minn=min(minn,a[i].v);
sort(a+,a+n+);
for(int i=;i<=n;i++)
if(a[i].id!=i){
ll s=a[i].id,tot=b[i],l=,mn=b[i];
while(s!=i){
l++;
mn=min(mn,b[s]);
tot+=b[s];
swap(a[s].id,s);
}
if(mn==minn)ans+=tot+mn*(l-);
else ans+=min(minn*(l+)+mn+tot,tot+mn*(l-));
}
cout<<ans;
return ;
}

P2127 序列排序的更多相关文章

  1. [洛谷P2127] 序列排序

    洛谷题目链接:序列排序 题目描述 小C有一个N个数的整数序列,这个序列的中的数两两不同.小C每次可以交换序列中的任意两个数,代价为这两个数之和.小C希望将整个序列升序排序,问小C需要的最小代价是多少? ...

  2. 洛谷 P2127 序列排序

    https://www.luogu.org/problemnew/show/P2127 感觉题解里写的比较复杂,可能自己的想法比较简单一点吧. 看这个图中的的点如果形成一个环,贪心的考虑,要想花费最少 ...

  3. 洛谷P2127 序列排序 [贪心]

    题目传送门 题目描述 小C有一个N个数的整数序列,这个序列的中的数两两不同.小C每次可以交换序列中的任意两个数,代价为这两个数之和.小C希望将整个序列升序排序,问小C需要的最小代价是多少? 输入输出格 ...

  4. 从无序序列中求这个序列排序后邻点间最大差值的O(n)算法

    标题可能比较绕口,简单点说就是给你一个无序数列A={a1,a2,a3……an},如果你把这个序列排序后变成序列B,求序列B中相邻两个元素之间相差数值的最大值. 注意:序列A的元素的大小在[1,2^31 ...

  5. 【洛谷P2127】序列排序

    题目大意:给定一个长度为 N 的序列,序列中的数两两不相同,每次可以交换序列中任意两个数,代价为这两个数的和,问将序列调整为升序,最少的代价是多少. 题解:考虑这个问题的一个子问题,这个序列为 N 的 ...

  6. python学习-序列排序

    python的排序中,可以使用内置的sort()来对序列进行排序,也可以使用内置的sorted()函数对序列进行排序,区别是,当使用sort()时,是对原序列进行排序,而sorted()则是生成一个新 ...

  7. [LeetCode] Permutation Sequence 序列排序

    The set [1,2,3,…,n] contains a total of n! unique permutations. By listing and labeling all of the p ...

  8. 【Excel】将IP按照IP地址(v4)增长序列排序

    Background: Excel列中,有多个net-block, 将这些net-block按照IP地址(v4)自己的大小从小到大排序. Idea: IPv4地址的格式是点分十进制的,也就是说每一个点 ...

  9. List集合序列排序的两种方法

    首先讲一下Comparable接口和Comparator接口,以及他们之间的差异.有助于Collections.sort()方法的使用.请参考 1.Comparable自然规则排序//在自定义类Stu ...

随机推荐

  1. 揭开js之constructor属性的神秘面纱

    揭开 constructor 在 Javascript 语言中,constructor 属性是专门为 function 而设计的,它存在于每一个 function 的prototype 属性中.这个 ...

  2. Java : java基础(1)

    java编译器有常亮优化机制,如果是常量的计算,会直接判断常量计算结果的取值范围,如果是变量,则没办法判断计算取值范围,编译会异常(如两个byte类型的变量相加). java中的常量指的是用 stat ...

  3. 齐博cms最新SQL注入网站漏洞 可远程执行代码提权

    齐博cms整站系统,是目前建站系统用的较多的一款CMS系统,开源,免费,第三方扩展化,界面可视化的操作,使用简单,便于新手使用和第二次开发,受到许多站长们的喜欢.开发架构使用的是php语言以及mysq ...

  4. (杭电 1097)A hard puzzle

    A hard puzzle Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total ...

  5. C++拷贝构造函数 的理解

    #include <iostream> using namespace std; //拷贝构造函数的理解 class Point { public: Point(); Point(int ...

  6. linux中常用命令总结

    一关机/重启/注销 关机 shutdown -h now //立即关机 重启 shutdown -r now //立即重启 reboot 重新启动 注销 logout //退出注销当前用户窗口 exi ...

  7. python2.7入门---列表(List)

        序列是Python中最基本的数据结构.序列中的每个元素都分配一个数字 - 它的位置,或索引,第一个索引是0,第二个索引是1,依此类推.Python有6个序列的内置类型,但最常见的是列表和元组. ...

  8. linux进程 生产者消费者

    #include<stdio.h> #include<unistd.h> #include<stdlib.h> #include<string.h> # ...

  9. ChemDraw Std 14性价比最高版本,即将下架

    虽然ChemDraw Std 14是ChemOffice®14的基础组件,但是基础功能涵盖全面,是教育专供产品.根据官方最新消息ChemDraw系列软件产品线将进行全面的升级,ChemOffice®1 ...

  10. 4.HBASE数据迁移方案(之snapshot):

    4.HBASE数据迁移方案:  4.1 Import/Export  4.2 distcp  4.3 CopyTable  4.4 snapshot 快照方式迁移(以USER_info:user_lo ...