首页 > 技术文章 > 2018ECNA Difference[时空复杂度]

hardcoreYutian 2019-08-19 21:36 原文

题干


代码和解释

本题给出一个数列的第一个数A(1),要求找出m第一次出现(直接出现在数列中或是数列中某两项的差的绝对值)在这个数列的第几步中。数列递推公式:A(n+1)=A(n)+min,min是最大的从1开始未出现在数列中且未出现在数列中某两项的差值的绝对值中的整数。
第一遍做此题时,我定义了一个结构体node存储每一步时数列的值以及这项与之前所有项的差值,并定义了这个结构体类型的vector来存储所有项及差值,同时定义了一个整型数组bul存储每一个数是否出现过的信息;

第二遍删去了结构体,用一个整数存数列中某项的值,并定义了一个整型的vector存储所有项,定义了一个数组diffs存储数列中某项与之前所有项值的差值,同时定义了一个整型数组bul存储每一个数是否出现过的信息;

这两次都以Runtime Error失败,在老师的指导下,我知道了自己第二遍的代码中bul和diffs两个数组占内存大小已达1.6个g之多(int型4个字节,(410^8)4个字节),严重超出内存要求,老师建议我使用char型数组代替bul,同样可以达到要求,且char型只占1个字节。而我也发现,diffs这个用于存储差值的数组并没有存在的必要,删去之。第三遍代码上交后报错为time limit exceeded,这时我想到最近刚学了list添加和删除元素要比vector快,于是将v改成list型,成功ac了。

下面是最终的c++代码

#include<iostream>
#include<list>
#include<string.h>
using namespace std;
char bul[200000005];//因为数组太大,放到全局变量可以解决这个问题。使用char型可以解决int型超出内存的问题! 
int main()
{
	int tv;//temporary value
	list<int> v;
	int A1;
	long long m;
	int i,j,f;
	int min;
	int tmp;
	int lastk;
	list<int>::iterator it;
	list<int>::iterator it2;
	while(~scanf("%d%lld",&A1,&m)){	
		v.clear();//初始化 
		tv=A1;
		v.push_back(tv);
		if(m==A1){
			printf("%d\n",1);
			break;
		}
		min=A1;
		memset(bul,'0',sizeof(bul));//初始化 
		bul[A1]='1';//第一个值有了 
		f=0;
		long long k = 1;//k存新的未出现的数 
		while(f==0){
			//先是添加,只要跟v的上一位比较即可 
			lastk=k;
			//寻找min的值 
			while(1){
				if(bul[k]=='0'){
					min=k;
					k++;
					break;
				}
				k++;				
			} 	
			it=v.end();
			it--;//表示比v.size()少一位的大小 
			tv=*it+min;
			bul[tv]='1';//这个值有了 
			bul[min]='1';// 
					
			for(it2=v.begin();it2!=it;it2++){//这里不能用小于号,只能用不等号 
				bul[tv-*it2]='1';//新出现的差值 
			}
			v.push_back(tv);			
			
			//再是查找是否有m,只要找v最新的一位即可
			if(bul[m]=='1'){
				printf("%d\n",v.size());
				break;
			}
		}
	}
	return 0; 
} 

解决本题使我认识到了做题时要注意考虑内存和时间,以及一些其他小教训,比如定义大的数组应该定义为全局变量,在结构体中定义数组要指明数组大小等。

推荐阅读