VP Codeforces Round 892 (Div. 2)


A. United We Stand

题意:把\(a\)分成两个不为空的数组,使得第二个数组的任意一个数不是第一个数组任意一个数的因子。

如果第二个数组的数都比第一个大就符合条件。无解的情况就是数组的数都相同。

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

    std::sort(a.begin(), a.end());
    if (a[0] == a.back()) {
    	std::cout << -1 << "\n";
    	return;
    }

    for (int i = 0; i < n; ++ i) {
    	if (a[i] != a.back()) {
    		b.push_back(a[i]);
    	} else {
    		c.push_back(a[i]);
    	}
    }

    std::cout << b.size() << " " << c.size() << "\n";
    for (int i = 0; i < b.size(); ++ i) {
    	std::cout << b[i] << " ";
    }
    std::cout << "\n";
    for (int i = 0; i < c.size(); ++ i) {
    	std::cout << c[i] << " ";
    }
    std::cout << "\n";
}

B. Olya and Game with Arrays

题意:\(n\)个数组每个数组把一个元素给其它数组,然后价值为每个数组的最小值之和。

先把每个数组的最小值拿出来,然后给剩下数组里最小值最小的那个数组。

点击查看代码
void solve() {
    int n;
    std::cin >> n;
    std::vector<std::vector<int>> a(n);
    int min = 2e9;
    for (int i = 0; i < n; ++ i) {
    	int m;
    	std::cin >> m;
    	for (int j = 0; j < m; ++ j) {
    		int x;
    		std::cin >> x;
    		a[i].push_back(x);
    	}

    	std::sort(a[i].begin(), a[i].end(), std::greater<int>());
    	min = std::min(min, a[i].back());
    	a[i].pop_back();
    }

    int min1 = 2e9;
    i64 ans = 0;
    for (int i = 0; i < n; ++ i) {
    	ans += a[i].back();
    	min1 = std::min(min1, a[i].back());
    }

    ans = ans - min1 + min;
    std::cout << ans << "\n";
}

C. Another Permutation Problem

题意:排列的价值为\((\sum_{i=1}^{n} p_i \times i) - (\max_{i=1}^{n} p_i \times i)\),求最大价值。

打表发现最大价值的数组一定使翻转了某个后缀。枚举翻转的后缀就行。

点击查看代码
void solve() {
    int n;
    std::cin >> n;
    i64 ans = 0;
    for (int k = 1; k <= n + 1; ++ k) {
    	i64 sum = 0, max = 0;
    	i64 x = 1;
    	for (int i = 1; i < k; ++ i) {
    		sum += x * i;
    		max = std::max(max, x * i);
    		++ x;
    	}

    	x = n;
    	for (int i = k; i <= n; ++ i) {
    		sum += x * i;
    		max = std::max(max, x * i);
    		-- x;
    	}

    	ans = std::max(ans, sum - max);
    }

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

D. Andrey and Escape from Capygrad

题意:\(n\)个四元组\((l_i, r_i, x_i, y_i)\)表示可以从\([l_i, r_i]\)任意一个位置到\([x_i, y_i]\)任意一个位置。\(q\)次询问每次问\(x\)最远能走到哪里。

先把出现过的数都离散化。
按照\(r_i\)从大到小排序,然后从大到小枚举\(i\),每次把\(r_i == i\)的加进大根堆,并用\(multiset\)记录\(y_i\)的值。这样就表示了所有覆盖\(i\)线段可以让\(i\)走到的最远距离。用并查集把\(i\)\(\max y_i\)合并。

点击查看代码
struct DSU {
	std::vector<int> fa, cnt;
	DSU(int _n) {
		init(_n);
	}

	void init(int _n) {
		fa.assign(_n, 0);
		cnt.assign(_n, 1);
		std::iota(fa.begin(), fa.end(), 0);
	}

	int find(int x) {
		return x == fa[x] ? x : fa[x] = find(fa[x]);
	}

	bool merge(int x, int y) {
		x = find(x), y = find(y);
		if (x == y) {
			return false;
		}

		fa[y] = x;
		cnt[x] += cnt[y];
		return true;
	}

	bool same(int x, int y) {
		return find(x) == find(y);
	}

	int size(int x) {
		return cnt[find(x)];
	}
};

void solve() {
    int n;
    std::cin >> n;
    std::vector<std::array<int, 4>> a(n);
    std::vector<int> b;
    for (int i = 0; i < n; ++ i) {
    	int l, r, L, R;
    	std::cin >> l >> r >> L >> R;
    	a[i] = {l, r, L, R};
    	b.push_back(l);
    	b.push_back(r);
    	b.push_back(L);
    	b.push_back(R);
    }

    int q;
    std::cin >> q;
    std::vector<int> Q(q);
    for (int i = 0; i < q; ++ i) {
    	std::cin >> Q[i];
    	b.push_back(Q[i]);
    }

    std::sort(b.begin(), b.end());
    b.erase(std::unique(b.begin(), b.end()), b.end());
    int m = b.size();
    auto get = [&](int x) -> int {
    	return std::lower_bound(b.begin(), b.end(), x) - b.begin();
    };

    for (auto & [l, r, L, R] : a) {
    	l = get(l);
    	r = get(r);
    	L = get(L);
    	R = get(R);
    }

    for (auto & x : Q) {
    	x = get(x);
    }

    DSU dsu(m);
    std::sort(a.begin(), a.end(), [&](std::array<int, 4> & a, std::array<int, 4> & b) {
    	return a[1] > b[1];
    });

    std::priority_queue<std::pair<int, int>> heap;
    std::multiset<int> s;
    for (int i = m - 1, j = 0; i >= 0; -- i) {
    	while (heap.size() && heap.top().first > i) {
    		s.extract(heap.top().second);
    		heap.pop();
    	}

    	while (j < n && a[j][1] == i) {
    		heap.push({a[j][0], a[j][3]});
    		s.insert(a[j][3]);
    		++ j;
    	}

    	if (s.size() && *s.rbegin() > i) {
    		dsu.merge(*s.rbegin(), i);
    	}
    }

    for (int i = 0; i < q; ++ i) {
    	std::cout << b[dsu.find(Q[i])] << " \n"[i == q - 1];
    }
}

E. Maximum Monogonosity

题意:给你两个数组\(a, b\),一个线段的价值为\(|b_l - a_r| + |b_r - a_l|\)。你要使用总长度为\(k\)的线段。求最大价值。

\(f[i][j]\)表示前\(i\)个位置用了总长度为\(j\)的最大值,转移方程就是枚举包含\(i\)的这一段有多长:\(f[i][j] = \max_{k=1}^{j} f[i - k][j - k] + |b_{i - k + 1} - a_i| + |b_i - a_{i-k+1}|\)。但这样是\(O(n^3)\)的时间复杂度,无法通过。先把绝对值拆开,总共有四种:

  1. \(f[i - k][j - k] + b_{i - k + 1} - a_i + b_i - a_{i - k + 1}\)
  2. \(f[i - k][j - k] + a_i - b_{i - k + 1} + b_i - a_{i - k + 1}\)
  3. \(f[i - k][j - k] + b_{i - k + 1} - a_i + a_{i - k + 1} - b_i\)
  4. \(f[i - k][j - k] + a_i - b_{i - k + 1} + a_{i - k + 1} - b_i\)

同时发现\(i\)\(j\)都是减\(k\),那么能转移到\(i, j\)\(x, y\)都满足\(i - j = x - y\)。那么我们可以\(g[l][t], t \in \{0, 1, 2, 3\}\)表示\(i - j = l\)的四种情况的\(f[i][j]\)的最大值。那么就可以拆开就行转移了。

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

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

    const i64 inf = 1e18;
    std::vector f(n + 1, std::vector<i64>(k + 1, -inf));
    std::vector g(n + 1, std::array<i64, 4>{-inf, -inf, -inf, -inf});
    f[0][0] = 0;
    //f[i][j] = f[i - k][j - k] + b[i - k + 1] - a[i] + b[i] - a[i - k + 1];
    //f[i][j] = f[i - k][j - k] + a[i] - b[i - k + 1] + b[i] - a[i - k + 1];
    //f[i][j] = f[i - k][j - k] + b[i - k + 1] - a[i] + a[i - k + 1] - b[i];
    //f[i][j] = f[i - k][j - k] + a[i] - b[i - k + 1] + a[i - k + 1] - b[i]
    for (int i = 1; i <= n; ++ i) {
    	f[i][0] = 0;
    	for (int j = 1; j <= std::min(k, i); ++ j) {
    		f[i][j] = f[i - 1][j];
    		g[i - j][0] = std::max(g[i - j][0], f[i - 1][j - 1] + b[i] - a[i]);
    		g[i - j][1] = std::max(g[i - j][1], f[i - 1][j - 1] - b[i] - a[i]);
    		g[i - j][2] = std::max(g[i - j][2], f[i - 1][j - 1] + b[i] + a[i]);
    		g[i - j][3] = std::max(g[i - j][3], f[i - 1][j - 1] - b[i] + a[i]);

    		f[i][j] = std::max(f[i][j], g[i - j][0] - a[i] + b[i]);
    		f[i][j] = std::max(f[i][j], g[i - j][1] + a[i] + b[i]);
    		f[i][j] = std::max(f[i][j], g[i - j][2] - a[i] - b[i]);
    		f[i][j] = std::max(f[i][j], g[i - j][3] + a[i] - b[i]);
    	}
    }

    std::cout << f[n][k] << "\n";
}
posted @ 2025-03-06 23:42  maburb  阅读(24)  评论(0)    收藏  举报