1056 组合数的和 (15 point(s))

// 不想思考暴力法
#include <bits/stdc++.h>
using namespace std;

int main() {
	// N 非零个位 任意两个组合成二位数字
	// 求所有可能组合数之和
	int n, sum = 0, a[10];
	cin >> n;
	for(int i = 0; i < n; i++)
		cin >> a[i];
		
	// 一重循环 固定第一个元素十位 
	for(int i = 0; i < n; i++){
		// 二重循环获取个位
		for(int j = i + 1; j < n; j++)
			sum += a[i] * 10 + a[j]; 
			
	}
	
	// 翻转再来一次 
	reverse(a, a + n);
	
	for(int i = 0; i < n; i++){
		// 二重循环获取个位
		for(int j = i + 1; j < n; j++)
			sum += a[i] * 10 + a[j]; 
			
	}
	
	cout << sum;
}
// 文艺简化版
#include <bits/stdc++.h>
using namespace std;

int main() {
	// N 非零个位 任意两个组合成二位数字
	// 求所有可能组合数之和
	int n, tmp, sum = 0;
	cin >> n;
	for(int i = 0; i < n; i++){
		cin >> tmp;
		sum += tmp;
	} 
	cout << sum * (n - 1) * 11;
}

看了看时间似乎没什么需求,况且是15分的题目,暴力一边过了。

本来还想这种组合会不会溢出,一看只有10个数并且还是两位,就没有考虑了。


学一下别人找规律。当时直接就想到的是排列组合,没想到还有人会往这个方向去想。

方法是先分类然后归纳关系,可以看到每个数字都会分别出现在个位和十位,比如 2 5 就有 25 和 52, 两个数分别做了一次个位和十位。当 2 8 , 5 8 时同理。

然后将这几个数字的全部组合列出来。

25 + 28 + 58 + 85 + 82 + 52

按照刚才的想法将个位和十位拆开分类。

20 + 5 + 20 + 8 + 50 + 8 + 80 + 5 + 80 + 2 + 50 + 2 =
20 + 20 + 50 + 50 + 80 + 80 + 2 + 2 + 5 + 5 + 8 + 8

可以看到在三个数的情况下,每个数在不同的位置上都出现了两次。用进制将他们化在一起就有。

2 * (20 + 50 + 80) + 2 * (2 + 5 + 8) =
2 * 10 * (2 + 5 + 8) + 2 * (2 + 5 + 8) =
2 * 11 * (2 + 5 + 8)

括号内是出现的数字相加,外面 11 是固定的, 2 是数字的个数减一 n - 1,这样就可以得到这题的比较简单的公式。

不过看不同位置出现次数,似乎之前哪个题目也有这样的思路。找了找是 1049 数列的片段和 这个题目。不过那个纯粹是因为暴力解不了,所以得找规律来化简一下。

至于是不是都是11这个常数可以自个多一两个数字验证一下,反正我也是剽窃来的只是随便解释一下。

公式推导

1056 组合数的和 (15 point(s))

上一篇:系统中的物理页框在Linux内核中都有struct page与之对应么?


下一篇:sed 替换命令使用