CCF计算机软件能力认证试题练习:202006-2 稀疏向量+探究数组长度上限+运行错误60分

文章目录

          • 一、原题
          • 二、探究数组最大能开多大
          • 三、数组长度上限

  • 局部变量的char数组最大能开4*518028,int最大能开到518028
  • 局部二维int数组能开到724*724
  • 全局一维int数组能开到很大很大…(2GB)
  • 全局二维int数组能开到20000*20000
一、原题

题目:

对于一个 n 维整数向量 v ∈ Zn,其在第 index 个维度上的取值记作 vindex。这里我们约定 index 的取值从 1 开始,即 v = (v1, v2, · · · , vn)。下面介绍一种向量的稀疏表示方法。
如果 v 仅在少量维度上的取值不为 0,则称其为稀疏向量。
例如当 n = 10 时,v = (0, 0, 0, 5, 0, 0,; 3, 0, 0, 1) 就是一个稀疏向量。
由于稀疏向量的非零值较少,我们可以通过仅存储非零值的方式来节省空间。具体来说,每个非零值都可以用一个 (index, value) 对来表示,即该向量在第 index 个维度上的取值 vindex = value ≠ 0。在上面的例子中,v 就可以表示为 [(4, 5), (7, 3), (10, 1)]。
接下来给出这种稀疏表示一般化的定义。
• 对于任意一个 n 维整数向量 v ∈ Zn,如果其在且仅在 a 个维度上取值不为 0,则可以唯一表示为:
[(index1, value1), (index2, value2), · · · , (indexa, valuea)] • 其中所有的 index 均为整数且满足:
1 ≤ index1 < index2 < · · · < indexa ≤ n
• valuei 表示向量 v 在对应维度 indexi 上的非零值。
给出两个 n 维整数向量 u, v ∈ Zn 的稀疏表示,试计算它们的内积。
u · v = ∑ ui · vi

输入

从标准输入读入数据。
输入的第一行包含用空格分隔的三个正整数 n、a 和 b,其中 n 表示向量 u、v 的维数,a 和 b 分别表示两个向量所含非零值的个数。
第二行到第 a + 1 行输入向量 u 的稀疏表示。第 i + 1 行(1 ≤ i ≤ a)包含用空格分隔的两个整数 indexi 和 valuei,表示 uindexi = valuei ≠ 0。 第 a + 2 行到第 a + b + 1 行输入向量 v 的稀疏表示。第 j + a + 1 行(1 ≤ j ≤ b)包含用空格分隔的两个整数 indexj 和 valuej,表示 vindex j = value j ≠ 0

输出

输出到标准输出。
输出一个整数,表示向量 u 和 v 的内积 u · v。

输入样例

10 3 4
4 5
7 -3
10 1
1 10
4 20
5 30
7 40

输出样例

-20

样例解释

u = (0, 0, 0, 5, 0, 0, 3, 0, 0, 1)
v = (10, 0, 0, 20, 30, 0, 40, 0, 0, 0)
u · v = 5 × 20 + (-3) × 40 = 20

数据规模:

CCF计算机软件能力认证试题练习:202006-2 稀疏向量+探究数组长度上限+运行错误60分_第1张图片

思路:没啥好说的,就两点注意:sum要long long,计算要用双指针做 O(n)

第一次提交:运行错误+60分

#include

using namespace std;

struct hashmap {
     
	int x = 0,y = 0;
};

int main()
{
     
	int n,a,b;
	scanf("%d %d %d",&n,&a,&b);
	hashmap hashmpu[a+5],hashmpv[b+5];
	for(int i=0;i<a;i++) scanf("%d %d",&hashmpu[i].x,&hashmpu[i].y);
	for(int i=0;i<b;i++) scanf("%d %d",&hashmpv[i].x,&hashmpv[i].y);

	int i = 0,j = 0;
	long long sum = 0;
	while(i<a && j<b) {
     
		int z=hashmpu[i].x,w=hashmpv[j].x;
		if(z == w) {
     
			sum += hashmpu[i].y*hashmpv[j].y;
			i++;j++;
		}
		if(z > w) j++;
		if(z < w) i++;
	}
	printf("%lld",sum);
	return 0;
}

思考:
1.已经注意到了sum的溢出,用的longlong,不会错。
2.除sum外,数据最大为10^9,int不会溢出
3.是运行错误,不是运行超时,双指针O(n)不会超时
4.运行错误大概率是内存溢出、指针越界(考虑定义数组的时候扩大长度)
第二次提交:正确+100分

#include

using namespace std;

const int max_a=5*100000+5,max_b=5*100000+5;
int u_key[max_a],u_val[max_a];
int v_key[max_b],v_val[max_b];

int main()
{
     
	int n,a,b;
	long long sum = 0;
	scanf("%d %d %d",&n,&a,&b);

	for(int i=0;i<a;i++) scanf("%d %d",&u_key[i],&u_val[i]);
	for(int i=0;i<b;i++) scanf("%d %d",&v_key[i],&v_val[i]);
 
	int i = 0,j = 0;
	while(i<a && j<b) {
     
		int z=u_key[i],w=v_key[j];
		if(z == w) {
     
			sum +=u_val[i]*v_val[j];
			i++;j++;
		}
		if(z > w) j++;
		if(z < w) i++;
	}
	printf("%lld",sum);
	return 0;
}

PS:保持ACM训练的良好代码习惯,定义长度用const int
尽量用全局变量

二、探究数组最大能开多大

通过上述两份代码,发现一个问题,代码的逻辑是相同的,为什么定义为全局变量就AC了呢?到底是指针越界还是内存溢出呢?
带着这个问题,设置第一个对比实验:
1.将第一份代码的

hashmap hashmpu[a+5],hashmpv[b+5];

改为:

hashmap hashmpu[5*100000+5],hashmpv[5*100000+5];

发现还是原来的错误:运行错误+60分
说明不是指针越界,而是内存溢出,既然是60分,说明问题出在最后四个数据
CCF计算机软件能力认证试题练习:202006-2 稀疏向量+探究数组长度上限+运行错误60分_第2张图片
代码本身与n无关,说明问题出在a,b上,能够溢出的地方,只有定义数组的地方:

//错误代码
//局部变量
hashmap hashmpu[a+5],hashmpv[b+5];
//正确代码
//全局变量
const int max_a=5*100000+5,max_b=5*100000+5;
int u_key[max_a],u_val[max_a];
int v_key[max_b],v_val[max_b];

考虑:是不是当a,b取到5*100000+5,数组过大溢出了呢?

三、数组长度上限

查询资料得知:
1.局部变量在栈上分配,最大2MB
2.全局变量在静态区分配,理论上是2GB

回到本题:一个struct的数组

//测试struct数组的内存大小
#include
using namespace std;
int main()
{
     
	cout << 2*(5*100000+5)*sizeof(int)/1024 << endl;
	return 0;
}

CCF计算机软件能力认证试题练习:202006-2 稀疏向量+探究数组长度上限+运行错误60分_第3张图片
3906/1024 > 3MB >2MB内存溢出,报“段错误
C++入门:C++数组可以开多大

  • 局部变量的char数组最大能开4*518028,int最大能开到518028
  • 局部二维int数组能开到724*724
  • 全局一维int数组能开到很大很大…(2GB)
  • 全局二维int数组能开到20000*20000

解决方法:
1.将逻辑上定义的struct拆分成两个数组,如代码所示

//原来的struct数组
struct hashmap {
     
	int x = 0,y = 0;
};
hashmap hashmpu[a+5],hashmpv[b+5];

//拆分成两个数组
//这样int的局部能开到518028,不会段错误
int u_key[max_a],u_val[max_a];
int v_key[max_b],v_val[max_b];

2 .将数组定义为全局变量

//这也是为什么ACM中习惯用const int + 全局变量的组合
const int max_a=5*100000+5,max_b=5*100000+5; 
hashmap hashmpu[max_a],hashmpv[max_b];

你可能感兴趣的:(PTA,蓝桥杯,leetocde,洛谷,深入理解计算机操作系统,算法)