2025.2.28 赛后总结

比赛链接

T1

注意到 wi 很小,枚举 w 即可。

Code

#include <bits/stdc++.h>

using namespace std;

const int kMaxN = 1e5 + 5;
int n, a[kMaxN], vis[205];

void S() {
	cin >> n;
	fill(vis + 1, vis + 201, 0);
	for (int i = 1; i <= n; ++i) {
		cin >> a[i];
		++vis[a[i]];
	}
	int mx = 0;
	for (int w = 2; w <= 200; ++w) {
		int cnt = 0;
		for (int i = 1; i <= 100; ++i) {
			if (w - i >= 1) {
				int x = i, y = w - i;
				if (x > y) {
					continue;
				}
				if (x == y) {
					cnt += (vis[x] >> 1);
				} else {
					cnt += min(vis[x], vis[y]);
				}
			}
		}
		mx = max(mx, cnt);
	}
	cout << mx << '\n';
	return;
}

int main() {
	cin.tie(0)->sync_with_stdio(false);
	int T;
	cin >> T;
	for (; T--;) {
		S();
	}
	return 0;
}

T2

发现 vi 可以用平方写,所以 dp 记录 wi 的总和,然后在所有的 fn,j 中寻找 wiW 的最大值即可。

Code

#include <bits/stdc++.h>
#define int long long

using namespace std;

int n, m, sum, dp[105][100005], w[105], val[105];

signed main() {
	cin.tie(0)->sync_with_stdio(false);
	cin >> n >> m;
	for (int i = 1; i <= n; ++i) {
		cin >> w[i] >> val[i];
		sum += val[i];
	}
	for(int i = 1; i <= sum; ++i) {
		dp[0][i] = 1e18;
	}
	dp[0][0] = 0;
	for (int i = 1; i <= n; ++i) {
		for (int j = 0; j <= sum; ++j) {
			dp[i][j] = dp[i - 1][j];
			if (j >= val[i]) {
				dp[i][j] = min(dp[i][j], dp[i - 1][j - val[i]] + w[i]);
			}
		}
	}
	for (int i = sum; i >= 0; --i) {
		if (dp[n][i] <= m) {
			cout << i;
			return 0;
		}
	}
	return 0;
}

T3

这题可以二分,但是直接暴力 check 会超时,所以使用双指针优化即可。

Code

#include <bits/stdc++.h>
#define int long long

using namespace std;

const int kMaxN = 1e5 + 5;
int n, k, a[kMaxN];
vector<int> e[kMaxN];

int check(int x) {
	int sum = (n - x) * x + x * (x - 1) / 2;
	for (int i = 1; i <= n; ++i) {
		for (int j = 0, l = 0; j < e[i].size(); ++j) {
			while (l < e[i].size() && e[i][j] - e[i][l] > x) {
				++l;
			}
			sum -= (j - l);
		}
	}
	return sum;
}

signed main() {
	cin.tie(0)->sync_with_stdio(false);
	cin >> n >> k;
	for (int i = 1; i <= n; ++i) {
		cin >> a[i];
		e[a[i]].emplace_back(i);
	}
	if (check(n) < k) {
		cout << -1;
		return 0;
	}
	int lt = -1, rt = n + 1;
	for (int mid; lt + 1 < rt;) {
		mid = lt + rt >> 1;
		if (check(mid) < k) {
			lt = mid;
		} else {
			rt = mid;
		}
	}
	int d = lt + 1, cnt = check(lt);
	for (int i = 1; i <= n - d; ++i) {
		if (a[i] != a[i + d]) {
			++cnt;
		}
		if (cnt == k) {
			cout << i << ' ' << i + d;
			return 0;
		}
	}
	return 0;
}

T4

考虑 DP,分两种情况,可以选和不能选,如果不能选,直接转移,否则使用堆记录能够选的满足条件的那个,然后再转移,这里可以选是不要从不选的那里转移的。

Code

#include <bits/stdc++.h>
#define int long long

using namespace std;

const int kMaxN = 1e5 + 5, kInf = 1e18;
int n, m, k, f[kMaxN][205];

struct Node {
	int s, t, d, w;
	bool operator<(const Node& rhs) const {
		if (w == rhs.w) {
			return d < rhs.d;
		}
		return w < rhs.w;
	}
} a[kMaxN];

bool cmp(Node x, Node y) {
	return x.s < y.s;
}

signed main() {
	cin.tie(0)->sync_with_stdio(false);
	cin >> n >> m >> k;
	for (int i = 1; i <= k; ++i) {
		cin >> a[i].s >> a[i].t >> a[i].d >> a[i].w;
	}
	sort(a + 1, a + k + 1, cmp);
	for (int i = 2; i <= n + 1; ++i) {
		for (int j = 0; j <= m; ++j) {
			f[i][j] = kInf;
		}
	}
	priority_queue<Node> h;
	for (int i = 1, j = 1; i <= n; ++i) {
		while (j <= k && a[j].s == i) {
			h.push(a[j]);
			++j;
		}
		while (!h.empty() && h.top().t < i) {
			h.pop();
		}
		if (h.empty()) {
			for (int l = 0; l <= m; ++l) {
				f[i + 1][l] = min(f[i + 1][l], f[i][l]);
			}
		} else {
			for (int l = 0; l <= m; ++l) {
				f[h.top().d + 1][l] = min(f[h.top().d + 1][l], f[i][l] + h.top().w);
			}
			for (int l = 0; l < m; ++l) {
				f[i + 1][l + 1] = min(f[i + 1][l + 1], f[i][l]);
			}
		}
	}
	int mn = kInf;
	for (int i = 0; i <= m; ++i) {
		mn = min(mn, f[n + 1][i]);
	}
	cout << mn;
	return 0;
}
posted @   scguo_931664  阅读(3)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
点击右上角即可分享
微信分享提示