当前位置:   article > 正文

蓝桥杯 — — 混乱的数组_混乱的数组蓝桥杯c

混乱的数组蓝桥杯c

混乱的数组

题目:

思路:

题目的基本意思是:给定一个数字x,找出一个数组,要求数组中有x对下标小的数其值更大的数对。我们可以利用逆序对来进行求解,如:3, 2, 1其逆序对分别为:2, 1, 0因此数组3, 2, 1的逆序对之和为3。

我们知道,逆序排序的序列的逆序对最大,并且逆序排列的序列求的逆序对的公式为: n × ( n − 1 ) 2 \frac{n\times(n - 1)}{2} 2n×(n1),其实这也是一个组合问题:如3, 2, 1其逆序可以这样思考:从这个序列中任意选择两个数,并且要求不重复,有:32,31,21这三个,可能会有人有这样的疑惑,如果是23,13,12是不是就不满足题目要求了?要知道,我们求的只是其组合个数,不用管其排列顺序,可以设定默认是按照从大到小的进行排列的。

求最大逆序对的程序

方式一:

int C(int n){
	return (n * (n - 1)) / 2;
}
  • 1
  • 2
  • 3

方式二:

int C(int n){
	int ans = 0;
	for(int i = 1;i < n;i++){
		ans += i;
	}
	return ans;
} 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

利用求最大逆序对,我们可以求出数组中有多少个数,即确定了结果中数字的个数。

如:7个数的最大逆序为:21,8个数的最大逆序为28

如果我们要求一个数的逆序为25,那么便确定了结果一共有8个数字,如:[8, 7, 6, 5, 1, 3, 2 ,1](题目要求只包含正整数)

显然这个结果满足逆序为25,但是不满足题目要求:最小字典序,我们可以继续进行优化,最终得到:[5, 4, 3, 3, 2, 2, 1, 1],满足最小字典序:

逆序对满足逆序对的最小字典序列
22265432 11
233543 2211
2444332211
2554 332211
266543 2211
27765432 11
2887654321

通过观察以上的表格,我们可以观察出以下规律:

  1. 如果给出的逆序对大于等于 ( C n 2 + C n − 1 2 ) 2 \frac{(C_n^2 + C_{n - 1}^2)}{2} 2(Cn2+Cn12),那么满足以下规律,斜体部分都是严格递减的,我们可以从后向前进行填充,先填充成对出现的(填充的个数为 C n 2 − x C_n^2 - x Cn2x个,x为需要求的逆序对的个数,即题目给出的x),并且使用一个变量用于计数,如果没有填充完毕,就进行严格的单调递增的进行填充,如果填充的长度满足求出的长度就结束填充,最后逆向输出即可。(如:逆序对为25,那么需要填充$C_8^2 - 25 = 28 - 25 = 3 $个成对出现的数字,然后再进行单调递增的填充4,5,6最后逆向输出即可)

  2. 如果给出的逆序对小于 ( C n 2 + C n − 1 2 ) 2 \frac{(C_n^2 + C_{n - 1}^2)}{2} 2(Cn2+Cn12),满足以下规律:依然是从后向前进行填充,其中重复数字部分填充 x − C n − 1 2 x - C_{n - 1}^2 xCn12次,填充完毕之后进行严格单调的填充,不填充最后一个数字,最后一个数字与 ( x − C n − 1 2 ) × 2 (x-C_{n - 1}^2) \times 2 (xCn12)×2个位置的值相等,即表格中加粗的部分的数字。(如:逆序对为23,那么需要填充 23 − C 7 2 = 2 23 - C_7^2 = 2 23C72=2次重复的数字,然后单调递增的进行填充到总长度-1个位置,最后一个位置的值等于 ( 24 − C 7 2 ) × 2 = ( 24 − 21 ) × 2 = 2 × 2 = 4 (24-C_7^2) \times 2 = (24 - 21) \times 2 = 2 \times 2 = 4 (24C72)×2=(2421)×2=2×2=4位置的值,实际上是第5个位置,因为数组的下标是从0开始的)

部分代码实现
		// i表示已经找到的数组的长度
		int oi = C(i - 1);
		int cut = (C(i) + oi) / 2;  // 中间的情况
		if(l < cut){
			// 短填充
			int tempc = l - C(i - 1);
			int idx = tempc * 2;
			int num = 1;
			int numlen = 0;
			while(numlen < i - 1){
				if(tempc > 0){
					ans.push_back(num);
					ans.push_back(num);
					tempc--;
					num ++;
					numlen += 2;
				}else{
					ans.push_back(num);
					num++;
					numlen += 1;
				}
				
			}
			ans.push_back(ans[idx]);   // 最后一位数字 
			 
		}else{
			// 长填充
			int tempc = C(i) - l ;
			int num = 1;
			int numlen = 0;
			while(numlen < i){
				if(tempc > 0){
					ans.push_back(num);
					ans.push_back(num);
					tempc--;
					numlen += 2;
				}else{
					ans.push_back(num);
					numlen += 1;
				}
				num++;
			}
		}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43

代码:

// 混乱的数组
#include<iostream>
using namespace std;
#include<vector>

// 求C_n^2  如果是选择2个数进行组合,数学公式(n * (n - 1)) / 2
int C(int n){
	return (n * (n - 1)) / 2;
}

//int C(int n){
//	int ans = 0;
//	for(int i = 1;i < n;i++){
//		ans += i;
//	}
//	return ans;
//} 

void solve(){
	int l = 0;
	cin>>l;
//	cout<<C(5)<<endl; 
	int i = 2;
	bool flag = false;
	while(true){
		if(C(i) == l){
			flag = true;
			break;
		}else if(C(i) > l){
			break; 
		}else{
			i++;
		}
	}
	
	cout<<i<<endl;
	if(flag){   // 表示找到了数组
		for(int k = i;k > 0;k --) cout<<k<<' '; 
	}else{
		vector<int> ans;
		int oi = C(i - 1);
		int cut = (C(i) + oi) / 2;  // 中间的情况
		if(l < cut){
			// 短填充
			int tempc = l - C(i - 1);
			int idx = tempc * 2;
			int num = 1;
			int numlen = 0;
			while(numlen < i - 1){
				if(tempc > 0){
					ans.push_back(num);
					ans.push_back(num);
					tempc--;
					num ++;
					numlen += 2;
				}else{
					ans.push_back(num);
					num++;
					numlen += 1;
				}
				
			}
			ans.push_back(ans[idx]);   // 最后一位数字 
			 
		}else{
			// 长填充
			int tempc = C(i) - l ;
			int num = 1;
			int numlen = 0;
			while(numlen < i){
				if(tempc > 0){
					ans.push_back(num);
					ans.push_back(num);
					tempc--;
					numlen += 2;
				}else{
					ans.push_back(num);
					numlen += 1;
				}
				num++;
			}
		}
		//进行逆序输出结果数组
		for(int i = ans.size() - 1;i >= 0;i --){
			cout<<ans[i]<<' '; 
		}
	}
	
	return ;
}


int main(){
	int t = 1;
	while(t--){
		solve();
	} 
	
	return 0;
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/1013485
推荐阅读
相关标签
  

闽ICP备14008679号