洛谷P2127 序列排序 [贪心]

  题目传送门

  


题目描述

小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,输入数据中的其他整数均为正整数且不超过109。



  

  分析:很显然的贪心。因为每次只能交换两个数,那么每次都拿小的数来交换肯定会更优。但肯定不会这么简单。首先从样例分析,样例中的8,2,7这三个数只要互相交换就可以到达目标位置,也就是说这三个数形成了一个“环”,那么每次就照这样的环,将环中的每一个数归位的最小花费只有两种情况:要么就每次都拿环中最小的数与每一个数相互交换,要么就拿整个序列中最小的数与环中每个数交换。不过要注意,第二种情况交换的时候有一个数会交换两次(可以自己模拟一下),那么肯定就将环中最小的数交换两次最优。具体看代码:

  Code:

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<cstdlib>
 4 #include<cmath>
 5 #include<iostream>
 6 #include<iomanip>
 7 #include<algorithm>
 8 using namespace std;
 9 const int N=1e5+7;
10 int n;
11 bool vis[N];
12 long long ans;
13 struct Node{
14   int val,pos;
15 }a[N];
16 inline int read()
17 {
18   char ch=getchar();int num=0;bool flag=false;
19   while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)flag=true;ch=getchar();}
20   while(ch>=‘0‘&&ch<=‘9‘){num=num*10+ch-‘0‘;ch=getchar();}
21   return flag?-num:num;
22 }
23 bool cmp(Node x,Node y)
24 {return x.val<y.val;}
25 inline void work(int x)
26 {
27   long long tot=0,num=0,minn=1e9+7;
28   while(!vis[x]){
29     vis[x]=true;tot++;
30     num+=a[x].val;
31     if(a[x].val<minn)
32       minn=a[x].val;
33     x=a[x].pos;}
34   long long a1=num+(tot-2)*minn;
35   //第一种情况最小的数只需要交换tot-1次
36   long long a2=num+(tot+1)*a[1].val+minn;
37   //第二种情况,如果用整个序列中最小的数交换则需交换(tot-1)次
38   ans+=min(a1,a2);
39 }
40 int main()
41 {
42   n=read();
43   for(int i=1;i<=n;i++){
44     a[i].val=read();
45     a[i].pos=i;}
46   sort(a+1,a+n+1,cmp);
47   for(int i=1;i<=n;i++)
48     if(!vis[i])
49       work(i);
50   printf("%lld",ans);
51   return 0;
52 }

原文地址:https://www.cnblogs.com/cytus/p/8929775.html

时间: 2024-08-13 23:41:32

洛谷P2127 序列排序 [贪心]的相关文章

洛谷P1969 积木大赛 贪心 差分

洛谷P1969 积木大赛 贪心 考虑差分 对区间 [l,r]+1 在差分数组上相当于 d[ l ]++ ; d[ r+1 ]-- ; 那么你得到原数组的差分数组后 当d[ i ] = x 则你需要 对 以 i 为左端点 右端点未知的一个区间加x次且这x加的可能不是同一个区间 所以最后只要将差分数组中所有正数加上去就行了 同样其实也可以用负数算的,但是负数算的话,要加上 d[ n+1 ] 即 a[ n+1 ] - a[ n ] 或者另一种思路对于一段上升(不下降)区间,我们在搭最高层时可以把下面一

洛谷P1654 产品排序(sort)

P1654 产品排序(sort) 题目描述 有一系列产品,给定每个产品的加工时间和冷却成型时间(冷却过程产品之间没有关系,是单独冷却的).现在你手上有两台机器可以用来加工,你需要安排产品加工的顺序以及去哪台机器加工,使得所有产品都成型的时间最早.机器之间互不相关,可以同时进行工作,一个机器一个时刻只能加工一个产品. 输入输出格式 输入格式: 第一行一个数n,表示产品个数,以下n行,每行两个数分别表示产品加工的时间A[i]和冷却时间B[i]. [数据规模] 对于20%的数据,满足n≤6: 对于10

洛谷P3165 [CQOI2014]排序机械臂

题目描述 为了把工厂中高低不等的物品按从低到高排好序,工程师发明了一种排序机械臂.它遵循一个简单的排序规则,第一次操作找到摄低的物品的位置P1,并把左起第一个至P1间的物品反序:第二次找到第二低的物品的位置P2,并把左起第二个至P2间的物品反序...最终所有的物品都会被排好序. 上图给出_个示例,第_次操作前,菝低的物品在位置4,于是把第1至4的物品反序:第二次操作前,第二低的物品在位罝6,于是把第2至6的物品反序... 你的任务便是编写一个程序,确定一个操作序列,即每次操作前第i低的物品所在位

洛谷P1250种树(贪心)

题目描述 一条街的一边有几座房子.因为环保原因居民想要在路边种些树.路边的地区被分割成块,并被编号成1..N.每个部分为一个单位尺寸大小并最多可种一棵树.每个居民想在门前种些树并指定了三个号码B,E,T.这三个数表示该居民想在B和E之间最少种T棵树.当然,B≤E,居民必须记住在指定区不能种多于区域地块数的树,所以T≤E-B+l.居民们想种树的各自区域可以交叉.你的任务是求出能满足所有要求的最少的树的数量. 写一个程序完成以下工作: 输入输出格式 输入格式: 第一行包含数据N,区域的个数(0<N≤

[洛谷P1631]序列合并

题目大意:给你两个非降序序列a和b,每个序列n个数,在a和b各取一个数相加,能得到$n^2$个和,求这些和中最小的n个. 解题思路:我们先把a[1]+b[1],a[1]+b[2],a[1]+b[3]...a[1]+b[n]扔进一个小根堆里,每次取出一个数,设为a[i]+b[j],那么我们输出这个数,并把a[i+1]+b[j]放进堆里,循环n次就能得出答案.时间复杂度$O(n\log n)$. 我用pbds的优先队列+pair实现,用第二个数保存a[i]+b[j]的i值. 然而我第一次push时i

洛谷P1327数列排序

题目描述 给定一个数列{an},这个数列满足ai≠aj(i≠j),现在要求你把这个数列从小到大排序,每次允许你交换其中任意一对数,请问最少需要几次交换? 输入输出格式 输入格式: 第一行,正整数n (n<=100,000). 以下若干行,一共n个数,用空格分隔开,表示数列{an},任意-231<ai<231. 输出格式: 只有一行,包含一个数,表示最少的交换次数. 输入输出样例 输入样例#1: 8 8 23 4 16 77 -5 53 100 输出样例#1: 5 ------------

洛谷 U361 序列操作(NOIP模拟赛T2)

题目链接:https://www.luogu.org/problem/show?pid=U361 题目背景 夏令营 题目描述 小B有一个整数序列a[1..N],初始时序列中所有元素均为0.他会在序列上进行下面两种操作,操作共M个: A l r x:将a[l..r]均加上x. Q l r:询问a[l..r]中的最大值. 输入输出格式 输入格式: 第一行,两个整数N, M. 接下来的M行,每行一个操作. 输出格式: 设询问操作有T个,则输出T行,每行一个整数,表示询问操作对应的答案. 输入输出样例

【洛谷】【堆+贪心】P1484 种树

[题目描述:] cyrcyr今天在种树,他在一条直线上挖了n个坑.这n个坑都可以种树,但为了保证每一棵树都有充足的养料,cyrcyr不会在相邻的两个坑中种树.而且由于cyrcyr的树种不够,他至多会种k棵树.假设cyrcyr有某种神能力,能预知自己在某个坑种树的获利会是多少(可能为负),请你帮助他计算出他的最大获利. [输入格式:] 第一行,两个正整数n,k. 第二行,n个正整数,第i个数表示在直线上从左往右数第i个坑种树的获利. [输出格式:] 输出1个数,表示cyrcyr种树的最大获利. 输

洛谷 P1430 序列取数

如果按照http://www.cnblogs.com/hehe54321/p/loj-1031.html的$O(n^3)$做法去做的话是会T掉的,但是实际上那个做法有优化的空间. 所有操作可以分解为由两步组成的操作:第一步是在数列的某一端取一个数并加到自己的得分上,第二步是把下一步操作的权利给自己或对方.如果这次操作的前一次是对方的操作,那么在左端或右端取数没有限制:如果这次操作的前一次是自己的操作,那么必须与上一次在相同的一端操作. 令ans[l][r][0/1/2]表示l到r的子序列,上一次