题目分析:
1、有一个数组A,里面有 n+1 个数,范围是 [0,N),注意,左闭右开,这个数组的特点是:
(1)第 0
位一定是 0,记 A[0] = 0
(2)数组 A 里的数越来越大
(3)最大的时候不能等于 N
(4)一共有 n+1 位
2、另有一个序号数组
,里面是自然数:0、1、2、3、4、5、、、、N-1。一共有 N 位
3、我们再规定一个数组 B(i),对应题目中的 f(i), 其特点是这样的:
(1)它的第 i 位的值等于 不超过序号数组
第 i 位的值 的数组A里的最大位号
(2)换言之,B(i) 里存的是数组 A 的某些满足条件的位号
(3)而这个所谓的条件就是:不超过序号数组第 i 位的值 的数组A里的最大位号
(4)一共有 N 位
例如:
A = {0
,2
,5
,8
}
序号数组 = { 0,1,2,3,4, 5, 6, 7,8,9}
那么由数组 B 的定义可知:
B 中第一位:数组 A 里的值不超过 0 的最大值的位号,即 0 的位号 0
B 中第二位:数组 A 里的值不超过 1 的最大值的位号,依然是 0 的位号 0
B 中第三位:数组 A 里的值不超过 2 的最大值的位号,即 2 的位号 1
B 中第四位:数组 A 里的值不超过 3 的最大值的位号,即 2 的位号 1
、、、、、
所以:
B = { 0,0,1,1,1,2,2,2,3,3}
4、知道 数组 B 后求出 B 的所有元素之和 sum
解题思路:
1、我们可以发现,只要求出 数组 B ,一切都好说了,求 sum
岂不是有手就行
2、数组 B 的位数与 序号数组 的位数相同,只是值不同
3、数组 B 的每一位的值也与 序号数组 有关
4、B 的每一位的值要么不变,要么加 1
:
{
0
,1,2
,3,4,5
, 6, 7,8
,9}
{ 0, 0, 1, 1, 1, 2, 2, 2, 3, 3}
5、很明显,变得时候(即需要加 1 的时候)都是 序号数组 的值等于数组 A 的值的时候
6、自然的,我们可以把需要变的位置记录先用数组下来,记为 1
,其余位置记为 0
7、与其说是 序号数组 的值等于数组 A 的值,不如说就是 序号数组的位数 等于 、数组 A 的值
8、因为第 0 位固定是 0 ,所以从第 1 位开始记录:
B[
0
] = 0
B[2
] = 1
B[5
] = 1
B[8
] = 1
即 B = {0,0,1
,0,0,1
,0,0,1
,0 }
9、现在我们把需要加 1
的位置记录下来了,现在B的值从0开始,需要加的时候,直接加就好了:
第 0 位肯定为0,所以从第 1 位开始:
for(i=1; i<N; i++) //B[0] = 0;
{
B[i] = B[i] + B[i-1];
}
最后得出真正的数组 B:B = { 0,0,1,1,1,2,2,2,3,3 }
代码实现(C++):
#include <stdio.h>
int main()
{
//n,代表下一行输入n个数,N代表共有N个序号,注意从0开始
int n, N;
scanf("%d %d", &n ,&N);
int B[N] = {0};
int i, j;
int sum = 0;
//注意A[0]固定为0,所以从A[1]开始存,到A[n]结束:
for(i=1; i<=n; i++)
{
scanf("%d", &j);
B[j]++; //标记出要变的位置,暂时用 B 记录
}
for(i=1; i<N; i++) //B[0] = 0;
{
B[i] = B[i] + B[i-1]; //求出真正的数组 B
sum = sum + B[i]; //求和
}
printf("%d",sum);
return 0;
}
另解(C语言):
我们直接从数组 A 数组 B 出发,找出规律,发现有 2-0 个 0,5-2 个 1,8-5 个 2,10-8 个 3,即:
A[1] - A[0]个 0
A[2] - A[1]个 1
A[3] - A[2]个 2
再加上,
N - A[3]个 3
#include <stdio.h>
int main()
{
//n,代表下一行输入n个数,N代表共有N个序号,注意从0开始
int n, N;
scanf("%d %d", &n ,&N);
int A[200] = {0};
int i;
int sum = 0;
//注意A[0]固定为0,所以从A[1]开始存,到A[n]结束:
for(i=1; i<=n; i++)
{
scanf("%d", &A[i]);
}
for(i=1; i<n; i++)
{
sum = sum + i*( A[i+1] - A[i] );
}
sum = sum + n*(N-A[n]);
printf("%d",sum);
return 0;
}