首页 > 其他分享 >P2127 序列排序 题解

P2127 序列排序 题解

时间:2023-07-28 09:14:34浏览次数:55  
标签:minn int 题解 sum minx num P2127 排序 100009

原题

题目意思

\(有一个数列a,每次可以挑选任意两个元素交换位置,代价为这两个元素的和,问把序列a升序排序所需的最小总代价\)
\(定义数列上的一个有i个元素的环S使得s_1要换到s_2,s_2要到s_3,……,s_i要到s_1\)
\(原图一个元素只有一个目标位置,所以可以看作一个有n点,n边的有向图\)
\(对于在一个大小为m的环S上的点,可以每次拿最小值进行交换,总次数为m-1次,总代价为环上总值加上最小值的额外代价\)
\(即sum_S+minn_S*(num_S-2)\)
\(易证,对于环内的其他交换方式,此方式为最优\)
\(对于没有在大环中的点,实际上在一个只有一个点的自环中,此公式同样成立\)
\(但,交换不一定要在环内进行,如\)
\(5\)
\(1\ 8\ 9\ 7\ 6\)
\(若只在环内交换,显然答案为9+6+8+6+7+6=42\)
\(但是可以{1,6}/{1,9}/{1,7}/{1,8}/{1,6}五次交换\)
\(1,8,9,7,6\)
\(6,8,9,7,1\)
\(6,8,1,7,9\)
\(6,8,7,1,9\)
\(6,1,7,8,9\)
\(1,6,7,8,9\)
\(总代价为1*5+6+9+8+7+6\)
\(设minx为整个数组最小值,易得公式为 minx*(num_S+1)+minn_S+sum_S\)
\(于是对于每个环,答案为min(sum_S+minn_S*(num_S-2),minx*(num_S+1)+minn_S+sum_S)\)
\(求环有很多方法,我这里用的tarjan\)

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,dfn[100009],low[100009],v[100009],cnt,cols,col[100009],q[100009],top;
struct dian
{
	int x,nd,v;
}a[100009];
bool cmp1(dian i,dian j)
{
	return i.v<j.v;
}
bool cmp2(dian i,dian j)
{
	return i.x<j.x;
}
int minn[100009],num[100009],sum[100009],ans;
void tarjan(int x)
{
	cnt++;
	dfn[x]=low[x]=cnt;
	q[++top]=x;
	v[x]=1;
	if(dfn[a[x].nd]==0)
	{
		tarjan(a[x].nd);
		low[x]=min(low[x],low[a[x].nd]);
	}
	else
	if(v[a[x].nd]==1)
	low[x]=min(low[x],dfn[a[x].nd]);
	if(low[x]==dfn[x])
	{
		cols++;
		int now;
		do
		{
			now=q[top];
			top--;
			col[now]=cols;
			minn[cols]=min(minn[cols],a[now].v);
			sum[cols]+=a[now].v;
			num[cols]++;
		}while(dfn[now]!=dfn[x]);
	}
}
signed main()
{
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		minn[i]=1e9+7;
		cin>>a[i].v;
		a[i].x=i;
	}
	sort(a+1,a+n+1,cmp1);
	int minx=a[1].v;
	for(int i=1;i<=n;i++)
	{
		a[i].nd=i;
	}
	sort(a+1,a+n+1,cmp2);
	for(int i=1;i<=n;i++)
	if(dfn[i]==0)
	tarjan(i);
	for(int i=1;i<=cols;i++)
	{
		ans+=min(minn[i]*(num[i]-2)+sum[i],minx*(num[i]+1)+sum[i]+minn[i]);
	}
	cout<<ans;
	return 0;
}

标签:minn,int,题解,sum,minx,num,P2127,排序,100009
From: https://www.cnblogs.com/tx-Elysia/p/17586674.html

相关文章

  • 【题解】[HNOI2015] 落忆枫音
    题目传送门感觉这题挺有意思的,遂写。题目大意给出一个有向无环图,再给定两个点\(s\)和\(t\),表示在点\(s\)和\(t\)间加上一条边。求这个图有多少种生成树。题目分析首先考虑不加边之前的情况,假设给定下面这个图:根据树的定义,除根节点外的节点有且只有一个父亲节点,也就......
  • 【AI夏令营】NLP赛题解析与Baseline逐行精读
    【任务】1.深入研读baseline代码,仔细理解其每个部分,并记录详尽的学习笔记;2.主动挑战自己,对基线代码进行优化,力求改进代码的实际效果和性能;3.完成任务二,并查看个人成绩排行榜。【Baseline精读】本次主要是针对任务二(关键词提取,也会有部分任务一的内容)首先是库文件的导入:#......
  • C语言快速排序及其优化操作
    快速排序原理简述:找到每一轮最大(最小)的数,依次从左到右存入新的数组,就完成了降序(升序)的排列。#include<stdio.h>intmain(void){intn;scanf("%d",&n);inta[n],temp;for(inti=0;i<n;i++){scanf("%d",&a[i]);}for(......
  • 2023-07-27:最长可整合子数组的长度, 数组中的数字排序之后,相邻两数的差值是1, 这种数组
    2023-07-27:最长可整合子数组的长度,数组中的数字排序之后,相邻两数的差值是1,这种数组就叫可整合数组。给定一个数组,求最长可整合子数组的长度。答案2023-07-27:算法maxLen的过程如下:1.检查输入数组是否为空,如果为空,则返回0,表示最长可整合子数组长度为0。2.初始化长度为1的最长......
  • Java 对json排序
    Java对JSON排序在日常的开发中,我们经常需要将JSON数据进行排序,以满足业务需求或者提高查询效率。本文将介绍如何使用Java对JSON数据进行排序,并提供示例代码帮助理解。什么是JSON?JSON(JavaScriptObjectNotation)是一种轻量级的数据交换格式,常用于前后端数据传输。它以......
  • AT_arc113_c 题解
    洛谷链接&Atcoder链接本篇题解为此题较简单做法及较少码量,并且码风优良,请放心阅读。题目简述现在有一个字符串\(S\),每一次你可以选择一个\(i(1\lei\le|S|)\),如果\(S_i=S_{i+1}\neS_{i+2}\)。就可以将\(S_{i+2}\)设为\(S_i\)求最多能操作几次。思路本......
  • 重建 题解
    重建题目大意给定一张无向图,第\(i\)条边存在的概率为\(p_i\),求这个无向图是一颗树的概率。思路分析所求即为:\[\sum_{T}\Bigg(\prod_{e\inT}p_e\Bigg)\Bigg(\prod_{e\not\inT}(1-p_e)\Bigg)\]其中,\(T\)是一个边集,当\(T\)中的边均存在时且其他边均不存在时,原图构成一......
  • AT_abc182_d 题解
    洛谷链接&Atcoder链接本篇题解为此题较简单做法及较少码量,并且码风优良,请放心阅读。题目简述从数轴的原点开始向正方向走。第一次向前走\(a_1\)步,第二次向前走\(a_1+a_2\),以此类推。求走过的最大位置。思路首先直接模拟时间复杂度\(O(n^2)\),看一下数据范围\((1\leN......
  • Lucky Array 题解
    LuckyArray题目大意维护一个序列,支持以下操作:区间加一个大于\(0\)的数。区间查询有多少个数位上只包含\(4\)或\(7\)的数。思路分析看起来很不可做,但考虑到题目给了一个特殊性质:保证所有数操作前后都不超过\(10^4\)。那么如果暴力进行区间加,最坏情况会加\(1......
  • P9017 [USACO23JAN] Lights Off G 题解
    Description给定正整数\(N\),和两个长为\(N\)的\(01\)序列\(a\)和\(b\)。定义一次操作为:将\(b\)序列中的一个值翻转(即\(0\)变成\(1\),\(1\)变成\(0\),下同)。对于\(b\)序列中每个值为\(1\)的位置,将\(a\)序列中对应位置的值翻转。将\(b\)序列向右循环移位......