首页 > 其他分享 >关于如何排序使得最终的答案最优的总结

关于如何排序使得最终的答案最优的总结

时间:2024-10-21 21:35:03浏览次数:1  
标签:总结 rand 二元 10 int pair 最优 排序 check

关于如何排序使得最终的答案最优的总结

例题

  1. Luogu P1012
  2. CF2024C

分析

就以先 CF2024C 来展开,题意是给定 \(N\) 个二元组,确定一个可行的排列使得最后的序列逆序对个数最少,注意二元组内部不可以交换顺序

Solution1

详情见 “CF980 Review” 中对这道题的解法,这里不多赘述了。

只是观察这种解法这道题有什么性质:
首先,我们定义的 \(A\) 比 \(B\) 更优,\(A\) 应该放在前面,是指 \(A\) 中的较大元素比 \(B\) 中的较大元素更小,或者说两者的较大值相等,但是前者的较小值更小。

按照我们的方法来交换相邻元素一定不会让答案变得更劣

不难观察到 如果 \(A\) 比 \(B\) 优,且 \(B\) 比 \(C\) 优,那么一定能够得出 \(A\) 比 \(C\) 优

Code
#include<bits/stdc++.h>
using namespace std;
template<typename T>inline void re(T &x)
{
	x=0;int f=1;char c=getchar();
	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
	while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
	x*=f;
}
template<typename T>inline void wr(T x)
{
	if(x<0)putchar('-'),x=-x;
	if(x>9)wr(x/10);
	putchar(x%10^48);
}
int T,n,m;
const int N=2e5;
pair<int,int> a[N];
inline bool cmp(pair<int,int> x,pair<int,int> y)
{
	int mx1,mn1,mx2,mn2;
	mx1=max(x.first,x.second),mx2=max(y.first,y.second);
	mn1=min(x.first,x.second),mn2=min(y.first,y.second);
	return (mx1==mx2?mn1<mn2:mx1<mx2);
}
int main()
{
	re(T);
	while(T--)
	{
		re(n);
		for(register int i=1;i<=n;++i)
		{
			re(a[i].first),re(a[i].second);
		}
		sort(a+1,a+n+1,cmp);
		for(register int i=1;i<=n;++i)
			wr(a[i].first),putchar(' '),wr(a[i].second),putchar(' ');
		putchar('\n');			
	}
	return 0;
}

Solution2

官方题解给出了一种更加简洁而且非常容易猜到的排序方式,虽然思维上面还是小有难度,但事实上看来赛时很多人都通过了这道题,这也印证了 oi 比赛不需要严格的证明,如果你猜的结论是正确的,那么就大胆地去应用,错了反正还可以再来,只是要罚时而已 (仅限非oi赛制)

我们只需要按照 \(A\) 这个二元组中两个元素的和把这个二元组序列升序排列就好。

证明可以通过分类讨论的方式来实现,

如果说 \(A\) 的和大于 $B $ 的和,那么要么 \(A\) 的两个值被夹在 \(B\) 的中间,要么 \(A\) 两个值 都比 \(B\) 的大。

在这两种情况下,我们交换 \(A\) 和 \(B\) 一定至少不会使得答案变得更差

而且,二元组内部的和的大小,如果 \(A\) 比 \(B\) 优,\(B\) 比 \(C\) 优,就一定有 \(A\) 比 \(C\) 优

Code
#include<bits/stdc++.h>
using namespace std;
template<typename T>inline void re(T &x)
{
	x=0;int f=1;char c=getchar();
	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
	while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
	x*=f;
}
template<typename T>inline void wr(T x)
{
	if(x<0)putchar('-'),x=-x;
	if(x>9)wr(x/10);
	putchar(x%10^48);
}
int T,n,m;
const int N=2e5;
pair<int,int> a[N];
inline bool cmp(pair<int,int> x,pair<int,int> y)
{
    return x.first+x.second<y.first+y.second;
}
int main()
{
	re(T);
	while(T--)
	{
		re(n);
		for(register int i=1;i<=n;++i)
		{
			re(a[i].first),re(a[i].second);
		}
		sort(a+1,a+n+1,cmp);
		for(register int i=1;i<=n;++i)
			wr(a[i].first),putchar(' '),wr(a[i].second),putchar(' ');
		putchar('\n');			
	}
	return 0;
}

Hack1

那么你会问 ,我为什么不能对于相邻的两个元素,直接比较他们交换位置前后的逆序对数量来定义他们的 优劣 呢?

而且好像似乎也满足 如果 \(A\) 比 \(B\) 优,\(B\) 比 \(C\) 优,就一定有 \(A\) 比 \(C\) 优 的性质。

那我们再仔细思考一下,以上两种解法,我们实际上并没有考虑 \(A=B\) 的情况,因为我们认定他们无论是否交换,对答案是不会存在影响的。

​ 在解法 1 中,\(A=B\) 则意味着两个二元组完全相等,所以显然没有影响。

​ 在解法 2 中,\(A=B\) 则意味着两个二元组要么是相同,要么是完全包含,可以证明如果有 \(B>C\) 或者 \(B=C\) ,就一定有 \(A\ge C\)。

但是在这种解法中,如果 \(A=B,B=C\) ,就不一定有 \(A=C\) 成立,一组hack数据如下。

4 7 ,2 9,7 3

Data generator
#include<bits/stdc++.h>
using namespace std;
int check(int x,int y,int i,int j)
{
	return (x>i)+(x>j)+(y>i)+(y>j); 
}
int main()
{
	int T=300;
	while(T--)
	{
		int x=rand()%10+1,y=rand()%10+1,i=rand()%10+1,j=rand()%10+1,n=rand()%10+1,m=rand()%10+1;
		int ans1=check(x,y,i,j),ans2=check(i,j,x,y);
		if(ans1>ans2)swap(x,i),swap(y,j);
		ans1=check(i,j,n,m),ans2=check(n,m,i,j);
		if(ans1>ans2)continue;
		if(!(check(x,y,n,m)<=check(n,m,x,y)))
			printf("%d %d %d %d %d %d\n",x,y,i,j,n,m);
	}
	return 0;
}

总结

解决这类问题的三个要素:

  1. 我们定义的交换相邻元素的方法不会使得答案变得更劣
  2. 我们定义的优劣比较具有传递性,更形式化地说,如果 $A\ge B,B\ge C $ ,那么必须有 \(A\ge C\) 。
  3. 务必要考虑等号的情况。

(注:上文的 “\(>\)” 代表 "前者比后者优")

标签:总结,rand,二元,10,int,pair,最优,排序,check
From: https://www.cnblogs.com/Hanggoash/p/18490464

相关文章

  • 小总结
    假如CSP寄了,这就是死亡回放没有简单题,不要总是想很快签。即使是黄也需要想一会,想不出来别慌,再不过先把暴力打出来。注意打特殊性质的分,复杂度不对也应该接着想,\(\mathbb{T}\)总比爆零好。容易忘的状压(数据范围较小时,也可以打部分分。)连通问题可以压与上一位是否连接。......
  • 模拟赛总结(三)
    2024.9.16重新定义饮料为一大杯冰沙胃:这把生死局(指抿一口就开始起反应...)早上就不停反呕,下午整这一出真是笑嘻了T1不相邻集合以为贪心假的,结果对了就是对新加的数看看有没有左邻右舍被取过,没有就计入答案codeT2线段树暴力\(20\)考虑到线段树开点方式,点编号之和肯定可......
  • 2024/10/21日工作总结
    实现jdbc的MySQL数据库连接;实现过程:在测试代码中导入数据库驱动jar包(mysql-connector-j-9.1.0.jar);注册驱动:"com.mysql.cj.jdbc.Driver";获取连接:"jdbc:mysql://localhost:3306/test",传入本地用户名称和密码;定义sql执行代码:更改数据库表格中的数据(updatetestsetmoney=100......
  • mongodb 查询条件,查询逻辑对照表,逻辑运算符,正则表达式匹配查询,排序,分页/巧分页,更新操
    mongodb查询条件,查询逻辑对照表,逻辑运算符,正则表达式匹配查询,排序,分页/巧分页,更新操作符,更新单个/多个文档,删除文档,批量插入,$type操作符,内嵌文档和数组查找修改1.条件查询SQLMQLa=1{a:1}a<>1{a:{$ne:1}}a>1{a:{$gt:1}}a>=1{a:{$gte:1}}a<1{a:{$lt......
  • 20241021比赛总结
    T1岛屿https://www.gxyzoj.com/d/hzoj/p/4177显然每个点只增加了一条边,最终每个点的度数都为2,所以最终必然是很多个环,连边的过程中,也必然是一些链和一些环由题,蓝同色链的个数和红同色链的个数相等,所以设\(f(a,b)\)为a条红同色链,b条异色链的期望考虑先处理异色链:红红连红蓝为......
  • 2024最新Java八股文总结!
    1、请写出你最常见的5个RuntimeException   难度系数:⭐java.lang.NullPointerException空指针异常;出现原因:调用了未经初始化的对象或者是不存在的对象。java.lang.ClassNotFoundException指定的类找不到;出现原因:类的名称和路径加载错误;通常都是程序试图通过字符串来加......
  • 今日总结
    四则运算importjavax.swing.;importjava.awt.;importjava.awt.event.ActionEvent;importjava.awt.event.ActionListener;importjava.io.*;importjava.util.ArrayList;importjava.util.List;importjava.util.Random;abstractclassProblemGenerator{protected......
  • 大模型驱动的电商个性化搜索结果重排序
    《大模型驱动的电商个性化搜索结果重排序》摘要随着电商行业的快速发展,个性化搜索成为了提升用户体验和提升转化率的关键因素。本文将探讨大模型驱动的电商个性化搜索结果重排序技术,分析大模型在电商搜索中的价值和应用原理。文章将详细介绍大模型的基础知识、电商搜索的......
  • 最强总结!十大回归类算法模型 !!!
     【转载】 最强总结!十大回归类算法模型!!! 今儿和大家分享的回归类算法有:线性回归Ridge回归Lasso回归弹性网络回归多项式回归决策树回归随机森林回归支持向量回归K近邻回归梯度提升回归1.线性回归线性回归是一种用于描述两个或多个变量......
  • whaosoftの图像知识总结
    搬来大佬的笔记啊为了给自己学习啊发贴没任何好处~~图像的组成图像的通道与深度深度:将计算机中存储单个像素所用的bit位,称为图像的深度例如:通道:描述一个像素点,如果是灰度图,只须用一个数值来表示,就是单通道。如果一个像素点有RGB三种颜色来描述,就是三通道,如果用RGB+alp......