高效算法设计

前言

众所周知,有一类题目题意很简单,但是必须优化时间复杂度,在这里纪念几道题目(心累了,码了这么多天了自己的水平还是捉襟见肘),但是我还是不想放弃—真的我特别想把一件事坚持下去。

题意

给定一个序列a[ n ],对于任意元素i,我们定义c [ i ] 为i + 1到n的第一个比它大的值的位置与a[ i ]的位置之差,求和c [ i ] 数组

这道题虽然解法非常简单但是我把它想复杂了。实际上这道题目就是维护i之前的元素单调这一信息,就可以顺利解决。这就是优化复杂度的常见方法之一, 线性扫描的同时不忘维护信息。

#include<bits/stdc++.h>
#define maxn 100000

using namespace std;
int a[maxn],res = 0;
int main(){
	int n;
	stack<int> st;
	cin >> n;
	for(int i = 0; i < n; i++){
		cin >> a[i];
		if(!st.empty()){
			while(!st.empty() && st.top() <= a[i])st.pop();
		}
		res += st.size();
		st.push(a[i]);
	} 
	cout << res <<endl;
	return 0;
}

第二道题目相对来说复杂点,是LA 3905 这道题目。
这道题目如果单纯的模拟流星的运动轨迹是不足以解决这道题目的。这是因为第一如果说时间的单位不能用计算机来模拟,我们关心的实际上是每个流星进入相机框框的时间,所以可以预处理这一信息。然后还是在线性扫描的同时,不能说计算,必须还是要维护信息。

代码就不放出来了

还是特别丧

明明校赛的题目我可以解决的是 tarjan缩点还有单调栈这样的题目
但就是一直过不去。脑子一直在分散注意力状态中。明明多想一步就是DAG了但还是一直过不去,真心烦。我还想继续弄下去。真不知道以后这个会不会是0产出

#include<bits/stdc++.h>
#define maxn 100010

using namespace std;

struct Event{
	double x;
	int type;
	bool operator < (const Event& a){
		return x < a.x || (x==a.x && type > a.type);
	}
} events[maxn*2];

void update(int x, int a, int w, double& L, double& R){
	if(a == 0){
		if(x <= 0 || x >= w) R = L-1;
	}else if(a > 0){
		L = max(L, -(double)x/a);
		R = min(R, (double)(w-x)/a);
	}else{
		L = max(L, (double)(w-x)/a);
		R = min(R, -(double)x/a);
	}
}

int main(){
	int T;
	scanf("%d",&T);
	while(T--){
		int w,h,n;
		scanf("%d%d%d", &w, &h, &n);
		int e=0;
		for(int i=0;i<n;i++){
			int x, y, a, b;
			scanf("%d%d%d%d", &x, &y, &a, &b);
			double L = 0, R = 1e9;
			update(x, a, w, L, R);
			update(y, b, h, L, R);
			if(R > L){
				events[e++] = (Event){L, 0};
				events[e++] = (Event){R, 1};
			}
		}
		sort(events,events+e);
		int cnt = 0, maxv = 0;
    	for(int i = 0; i < e; i++) {
      		int type = events[i].type;
			if(type == 0) maxv = max(maxv, ++cnt);
      		else cnt--;
    	}
    	printf("%d\n", maxv);
	}
	return 0;
}

算了,有的时候不多想也是一种聪明,还是继续加油吧。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值