寒假训练 2024/2/11凌晨

紫书

uva437

标签:

二位偏序,区间dp

题意:

给$n$种长方体,每种有无限块,要求罗列最高的高度。限制条件是在下面的长方体的长和宽要严格大于上面的。

思路:

思路很简单,题目给的$n 的 范围[1, 50]$,模拟一下我们可以推断,每一种长方体有$A_3^{3} = 6$ 种排列方式,我们把每一种的六种排列方式压入集合(只需要压入一遍,因为题目要求是严格小于),然后按照第一和第二关键字排序,最后区间dp就行。

复杂度:

O($m ^ 2$, m = 6n), 可行

#include <bits/stdc++.h>
using namespace std;

#define int long long
	
struct inf {
	int a, b, c;
};

bool cmp1 (inf A, inf B) {
	if(A.a == B.a) {
		return A.b < B.b;
	}
	return A.a < B.a;
}

void solve(int n, int Case) {
	vector<inf> v;

	for (int i = 0; i < n; i++) {
		int ta, tb, tc;
		cin >> ta >> tb >> tc;
		v.push_back({ta, tb, tc});
		v.push_back({ta, tc, tb});
		v.push_back({tb, ta, tc});
		v.push_back({tb, tc, ta});
		v.push_back({tc, ta, tb});
		v.push_back({tc, tb, ta});
	}

	sort(v.begin(), v.end(), cmp1);
	
	vector<int> dp(n * 6 + 1, 0);
	int ans = 0;
	for (int i = 1; i <= v.size(); i++) {
		for (int j = 0; j < i; j++) {
			if(!j || v[j - 1].a < v[i - 1].a && v[j - 1].b < v[i - 1].b) {
				dp[i] = max(dp[i], dp[j] + v[i - 1].c);
			}
		}
		ans = max(ans, dp[i]);
	}

	cout << "Case " << Case << ": maximum height = " << ans << endl;
}

signed main() {
	ios::sync_with_stdio(0);
	cin.tie(0), cout.tie(0);

	int n, cnt = 1;
	while(cin >> n && n) {
		solve(n, cnt++);
	}

	return 0;
}

uva10048

题意:

给了n$\le 100$个点,m$\le 1000$个条边,q$\le 10000$个个询问,

每个询问给初始点和终点,求经过边最大值的最小值。

思路:

起初我想到最大值最小,就想到了二分,但是这个题是边,直接走一遍就可以得出,我考虑用搜索,考虑到dfs之前出现过爆栈的情况,这次我选用bfs,每个bfs跑一边所有边,时间复杂度就是O(mq),可行。

#include <bits/stdc++.h>
using namespace std;

#define int long long

void solve(int Case) {
	int n, m, q;
	cin >> n >> m >> q;
	if(!n) {
		exit(0);
	}

	vector<vector<pair<int, int>>> adj(n + 1, vector<pair<int, int>>());

	for (int i = 0; i < m; i++) {
		int a, b, c;
		cin >> a >> b >> c;
		adj[a].push_back({b, c});
		adj[b].push_back({a, c});
	}

	auto f=[&] (int st, int ed) {
		vector<int> dis (n + 1, 1e18);

		dis[st] = 0;
		queue<int> q;
		q.push(st);
		int res = 1e18;
		while(q.size()) {
			auto x = q.front();
			// cerr << x << " " << dis[x] << endl;
			q.pop();
			if(x == ed) {
				continue;
			}	
			for (auto [ne, cos] : adj[x]) {
				if(dis[ne] > max(cos ,dis[x])) {
					q.push(ne);
					dis[ne] = max(cos, dis[x]);
				}
			}
		}

		return dis[ed];
	};

	if(Case > 1) {
		cout << endl;
	}
	cout << "Case " << "#" << Case << endl;

	for (int i = 0; i < q; i++) {
		int st, ed;
		cin >> st >> ed;
		int res = f(st, ed);
		if(res == 1e18) {
			cout << "no path\n";
		}
		else {
			cout << res << endl;
		}
	}
}

signed main() {
	ios::sync_with_stdio(0);
	cin.tie(0), cout.tie(0);

	// int T = 1;
	// cin >> T;
	int cnt = 1;
	while(1) {
		solve(cnt++);
	}

	return 0;
}

uva11572

题意:

求最长的区间:区间内没有重复的数字。

思路:

一眼哈希。需要注意的是有两段,开始到重复的第二个数字的前一个数字和第一个数字到第二个数字的前一个数字。

#include <bits/stdc++.h>
using namespace std;

#define int long long

void solve() {
	int n;
	cin >> n;

	vector<int>v(n);
	map<int, int>mp;

	int ans = 0;
	int st = 0;
	for (int i = 0; i < n; i++) {
		cin >> v[i];
		if(mp.count(v[i]) != 0 && mp[v[i]] >= st) {
			ans = max(max(ans, i - mp[v[i]]), i - st);
			st = mp[v[i]] + 1;
		}
		mp[v[i]] = i;
	}

	ans = max(ans, n - st);
	
	cout << ans << endl;
}

signed main() {
	ios::sync_with_stdio(0);
	cin.tie(0), cout.tie(0);

	int T = 1;
	cin >> T;
	while(T--) {
		solve();
	}

	return 0;
}
posted @ 2024-02-11 01:53  contiguous  阅读(20)  评论(0)    收藏  举报