VP Educational Codeforces Round 15


Educational Codeforces Round 15

题意:求严格递增子数组的最长长度。

双指针经典题。

点击查看代码
void solve() {
    int n;
    std::cin >> n;
    std::vector<int> a(n);
    for (int i = 0; i < n; ++ i) {
    	std::cin >> a[i];
    }

    int ans = 0;
    for (int i = 0; i < n; ++ i) {
    	int j = i;
    	while (j + 1 < n && a[j + 1] > a[j]) {
    		++ j;
    	}

    	ans = std::max(ans, j - i + 1);
    	i = j;
    }

    std::cout << ans << "\n";
}

B. Powers of Two

题意:求数组中有多少对的和是\(2\)的幂。

存每个数的个数,然后枚举\(2\)的幂统计。

点击查看代码
void solve() {
	int n;
	std::cin >> n;
	std::map<i64, int> mp;
	std::set<i64> s;
	for (int i = 0; i < n; ++ i) {
		i64 x;
		std::cin >> x;
		s.insert(x);
		++ mp[x];
	}    

	i64 ans1 = 0, ans2 = 0;
	for (i64 i = 1; i <= 30; ++ i) {
		for (auto & x : s) {
			if (!s.count((1ll << i) - x)) {
				continue;
			}
			if ((1ll << i) - x == x) {
				ans1 += (i64)mp[x] * (mp[x] - 1) / 2;
			} else {
				ans2 += (i64)mp[x] * mp[(1ll << i) - x];
			}
		}
	}

	std::cout << ans1 + ans2 / 2 << "\n";
}

C. Cellular Network

题意:有\(n\)个城市和\(n\)个电台在一个坐标轴上,求电台传播半径最小是多少可以让每个城市至少被一个电台覆盖。

二分长度,check里用差分写,找每个电台可以覆盖的最小坐标的城市和最大坐标的城市。

点击查看代码
void solve() {
    int n, m;
    std::cin >> n >> m;
    std::vector<i64> a(n), b(m);
    for (int i = 0; i < n; ++ i) {
    	std::cin >> a[i];
    }

    for (int i = 0; i < m; ++ i) {
    	std::cin >> b[i];
    }

    auto check = [&](i64 x) -> bool {
    	std::vector<int> d(n + 2);
    	for (int i = 0; i < m; ++ i) {
    		int l = std::lower_bound(a.begin(), a.end(), b[i] - x) - a.begin() + 1;
    		int r = std::upper_bound(a.begin(), a.end(), b[i] + x) - a.begin();
    		if (l <= r) {
    			++ d[l];
    			-- d[r + 1];
    		}
    	}

    	for (int i = 1; i <= n; ++ i) {
    		d[i] += d[i - 1];
    		if (d[i] <= 0) {
    			return false;
    		}
    	}

    	return true;
    };

    i64 l = 0, r = 2e9;
    while (l < r) {
    	i64 mid = l + r >> 1ll;
    	if (check(mid)) {
    		r = mid;
    	} else {
    		l = mid + 1;
    	}
    }

    std::cout << l << "\n";
}

D. Road to Post Office

题意:你要走\(d\)公里,车子每公里用时\(a\),且每走\(k\)公里需要维护\(t\)秒。步行没有限制,每公里用时\(b\)。求到达终点的最小时刻。

如果我们枚举车子走多少米,然后剩下的步行,会超时。但发现如果开车更优,那么我们应该一直开车,最后一段步行,或者直接一直开车。那么就可以分情况讨论,如果\(d < k\),直接开车直达。发现我们看一直开车更优还是步行更优,注意步行前我们应该把能开车的距离用掉。

点击查看代码
void solve() {
    i64 d, k, a, b, t;
    std::cin >> d >> k >> a >> b >> t;
    if (d < k) {
    	std::cout << a * d << "\n";
    	return;
    }

    i64 ans = k * a + (d - k) * b;
	ans = std::min(ans, t * (d / k) + d * a);{
	ans = std::min(ans, t * (d / k - 1) + (d - d % k) * a + b * (d % k));}
	std::cout << ans << "\n";
}

E. Analysis of Pathes in Functional Graph

题意:有一个\(n\)\(n\)边的有向图,每个点都恰好有一条出边。求每个点走\(k\)的距离的路径总和和路径上边权最小值。

可以考虑倍增,预处理\(son[i][j], sum[i][j], min[i][j]\)表示从\(i\)\(2^j\)距离到达的点、路径总和,路径最小边权。那么对于每个点就按照\(2\)的幂从大到小枚举跳。

点击查看代码
void solve() {
	int n;
	i64 k;
	std::cin >> n >> k;
	std::vector<int> f(n), w(n);
	for (int i = 0; i < n; ++ i) {
		std::cin >> f[i];
	}

	for (int i = 0; i < n; ++ i) {
		std::cin >> w[i];
	}

	const int inf = 2e9;
	const int lg = std::__lg(k) + 1;
	std::vector son(n, std::vector<int>(lg + 1));
	std::vector sum(n, std::vector<i64>(lg + 1));
	std::vector min(n, std::vector<i64>(lg + 1, inf));

	for (int i = 0; i < n; ++ i) {
		son[i][0] = f[i];
		sum[i][0] = w[i];
		min[i][0] = w[i];
	}	

	for (int j = 1; j <= lg; ++ j) {
		for (int i = 0; i < n; ++ i) {
			son[i][j] = son[son[i][j - 1]][j - 1];
			sum[i][j] = sum[i][j - 1] + sum[son[i][j - 1]][j - 1];
			min[i][j] = std::min(min[i][j - 1], min[son[i][j - 1]][j - 1]);
		}
	}

	for (int i = 0; i < n; ++ i) {
		i64 ans1 = 0, ans2 = inf;
		int u = i;
		for (i64 j = lg; j >= 0; -- j) {
			if (k >> j & 1) {
				ans1 += sum[u][j];
				ans2 = std::min(ans2, min[u][j]);
				u = son[u][j];
			}
		}

		std::cout << ans1 << " " << ans2 << "\n";
	}
}
posted @ 2025-02-24 16:36  maburb  阅读(8)  评论(0)    收藏  举报