CSP 202112-1 序列查询(详解)

题目分析:

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 = { 0258}
序号数组 = { 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;
 } 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

刘学.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值