学习笔记第一章

假设时间限制为1秒

106游刃有余
107勉勉强强
108很悬,仅结构体非常简单的情况

POJ No.1852

对于最短的时间来说,所有的蚂蚁都朝向较近的端点走是最快的。
对于最长的时间来说,两只蚂蚁遇见后折返,如果我们无视蚂蚁与蚂蚁之间的区别,其实就相当于两只蚂蚁一直以同一个方向前进然后走到终点。所以这个时候我们就可以以所有蚂蚁中离端点最远的一个作为答案。
题目链接

int L,N;
int x[max_n];
void solve(){
	int minT=0;//求最小时间,先判断当前点是往左走快还是右走快,然后从中取最大的。
	for(int i=0;i<N;i++){
		minT=max(minT,min(x[i],L-x[i]));
	}
	int maxT=0;
	for(int i=0;i<N;i++){
		maxT=max(maxT,max(x[i],L-x[i]));
	}
	cout << minT << endl << maxT << endl;
}
抽签问题
题目:

挑战程序设计竞赛page.2

O(n4)算法:

使用4层for循环嵌套,可求得答案,但将n=1000代入n4可以得到1012,直接回TLE。
算法改进:
假设原始算法采用a,b,c,d四个循环嵌套得到答案,那么最内层的循环d所作的事情就是检查是否有kd使得ka+kb+kc+kd=m,我们可以将式子移动一下,即检查是否有kd=m-ka-kb-kc,这样我们就可以检查数组中是否含有kd来减少最内层的循环。但是我们如何去判断kd在数组中呢?如果使用最朴素的做法就是依次遍历,可这样做了之后时间复杂度依然是O(n4)。所以我们这里采用二分的方法去寻找这个数,时间复杂度就退化为O(n3log2n)。
先将k数组进行排序,看k中央的数,如果比要查询的数字要大,那么我们查询左边,否则查询右边,直到找到了这个数。

int k[maxn],n,m;
bool binary_search(int x){
	int l=0,r=n;
	int mid;
	while(r-l>=1){//可操作数大于1
		int mid=(l+r)>>1;
		if(k[mid]==x)return true;
		else if(k[mid]>x)r=mid;
		else l=mid+1;
	}
	return false;
}
void solve(){
	for(int a=0;a<n;a++){
		for(int b=0;b<n;b++){
			for(int c=0;c<n;c++){
				if(binary_search(m-k[a]-k[b]-k[c])){
					cout << "Yes" << endl;
					return;
				}
			}
		}
	}
	cout << "No" << endl;
}

但是,将1000代入O(n3log2n),会发现这仍然不够,必须对算法进行进一步优化。刚才我们只着手了最后一个循环,接下来我们来看最后两个循环。
跟上面一个思路,检查是否有kc+kd=m-ka-kb,这种方法无法直接用二分,但是我们可以将kc+kd的每种情况保存起来并排序,然后就可以进行二分了。

int k[maxn],n,m,kk[maxn*maxn];//用于保存c*d的n^2种情况
bool binary_search(int x){
	int l=0,r=n*n;
	int mid;
	while(r-l>=1){//可操作数大于1
		int mid=(l+r)>>1;
		if(kk[mid]==x)return true;
		else if(kk[mid]>x)r=mid;
		else l=mid+1;
	}
	return false;
}
void solve(){
	int count_s=0;
	for(int c=0;c<n;c++){
		for(int d=0;d<n;d++){
			kk[count_s++]=k[c]+k[d];
		}
	}
	sort(kk,kk+count_s);
	for(int a=0;a<n;a++){
		for(int b=0;b<n;b++){
				if(binary_search(m-k[a]-k[b])){
					cout << "Yes" << endl;
					return;
			}
		}
	}
	cout << "No" << endl;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值