数位排序【第十三届蓝桥杯省赛C++C组】

数位排序

小蓝对一个数的数位之和很感兴趣,今天他要按照数位之和给数排序。

当两个数各个数位之和不同时,将数位和较小的排在前面,当数位之和相等时,将数值小的排在前面。

例如,\(2022\) 排在 \(409\) 前面,因为 \(2022\) 的数位之和是 \(6\),小于 \(409\) 的数位之和 \(13\)

又如,\(6\) 排在 \(2022\) 前面,因为它们的数位之和相同,而 \(6\) 小于 \(2022\)

给定正整数 \(n,m,\)请问对 $1 $到 \(n\) 采用这种方法排序时,排在第 \(m\) 个的元素是多少?

输入格式
输入第一行包含一个正整数 \(n\)

第二行包含一个正整数 \(m\)

输出格式
输出一行包含一个整数,表示答案。

数据范围
对于 \(30%\) 的评测用例,\(1≤m≤n≤300\)
对于 \(50%\) 的评测用例,\(1≤m≤n≤1000\)
对于所有评测用例,\(1≤m≤n≤106\)

输入样例:
13
5
输出样例:
3
样例解释
\(1\)\(13\) 的排序为:\(1,10,2,11,3,12,4,13,5,6,7,8,9\)

\(5\) 个数为 \(3\)

TLE(通过了 5/10个数据)

快排+过程处理

点击查看代码
#include<iostream>
#include<algorithm>
using namespace std;

int n,m; 
const int N = 1e6 + 10;
int a[N];

int get(int x){
	int ret = 0;
	while(x){
		ret += x % 10;
		x /= 10;
	}
	return ret;
}

bool cmp(int a,int b){
	if(get(a) != get(b))return get(a) < get(b);
	else return a < b;
}
int main(){
	cin >> n >> m;
	for(int i = 1; i <= n; i ++)a[i] = i;
	sort(a + 1,a + n + 1,cmp);
	cout << a[m];
	//for(int i = 1; i <= n; i ++)cout << a[i] << " ";
}

TLE(通过了 7/10个数据)

冒泡加过程处理

点击查看代码
#include<iostream>
#include<algorithm>
using namespace std;

int n,m;
const int N = 1e6 + 10;
int a[N];

int get(int x){
	int ret = 0;
	while(x){
		ret += x % 10;
		x /= 10;
	}
	return ret;
}

bool cmp1(int a,int b){
	if(get(a) != get(b))return get(a) > get(b);
	else return a > b;
}

bool cmp2(int a,int b){
	if(get(a) != get(b))return get(a) < get(b);
	else return a < b;
}
int main(){
	cin >> n >> m;
	for(int i = 1; i <= n; i ++)a[i] = i;
	if(m > n - m){
		for(int i = 1; i <= n - m + 1; i ++){
			for(int j = 1; j < n - i + 1; j ++){
				if(cmp1(a[j],a[j + 1]))swap(a[j],a[j + 1]);
			}
		}
		cout << a[m];
	}
	else{
		for(int i = 1; i <= m; i ++){
			for(int j = 1; j < n - i + 1; j ++){
				if(cmp2(a[j],a[j + 1]))swap(a[j],a[j + 1]);
			}
		}
		cout << a[n - m + 1];
	}
	//or(int i = 1; i <= n; i ++)cout << a[i] << " ";
	//cout << endl << a[m] << " " << a[n - m + 1];
}

Code(AC)\(O(nlogn)\)

快排+预处理 \(3489 ms\)

点击查看代码
#include<iostream>
#include<algorithm>
#include<vector> 
#define X first
#define Y second

using namespace std;

typedef pair<int,int> PII;
int n,m; 
const int N = 1e6 + 10;
vector<PII> q;

int get(int x){
	int ret = 0;
	while(x){
		ret += x % 10;
		x /= 10;
	}
	return ret;
}

bool cmp(PII a,PII b){
	if(a.Y != b.Y)return a.Y < b.Y;
	else return a.X < b.X;
}

int main(){
	cin >> n >> m;
	for(int i = 1; i <= n; i ++)q.push_back({i,get(i)});
	sort(q.begin(),q.end(),cmp);
	cout << q[m - 1].first;
}

Code(AC) \(O(n)\)

快速选择\(287 ms\)

点击查看代码
#include <iostream>
#include <algorithm>
using namespace std;

const int N = 1000010;

int n, m;
int w[N], s[N];

bool cmp(int a, int b)
{
    if (s[a] != s[b]) return s[a] < s[b];
    return a < b;
}

int quick_select(int l, int r, int k)
{
    if (l == r) return w[l];
    int x = w[l + r >> 1], i = l - 1, j = r + 1;
    while (i < j)
    {
        do i ++ ; while (cmp(w[i], x));
        do j -- ; while (cmp(x, w[j]));
        if (i < j) swap(w[i], w[j]);
    }
    if (k <= j) return quick_select(l, j, k);
    return quick_select(j + 1, r, k);
}

int main()
{
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i ++ )
    {
        w[i] = i;
        for (int j = i; j; j /= 10)
            s[i] += j % 10;
    }
    printf("%d\n", quick_select(1, n, m));
    return 0;
}

注意

  1. vector从0开始而不是1
  2. nlogn时间复杂度 -> 先对每个数进行预处理,保存数位和再进行排序,而不是排序过程中进行处理
posted @ 2023-01-05 13:27  Keith-  阅读(248)  评论(0编辑  收藏  举报