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

题意:排列的价值为(i=1npi×i)(maxi=1npi×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个四元组(li,ri,xi,yi)表示可以从[li,ri]任意一个位置到[xi,yi]任意一个位置。q次询问每次问x最远能走到哪里。

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

点击查看代码
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,一个线段的价值为|blar|+|bral|。你要使用总长度为k的线段。求最大价值。

f[i][j]表示前i个位置用了总长度为j的最大值,转移方程就是枚举包含i的这一段有多长:f[i][j]=maxk=1jf[ik][jk]+|bik+1ai|+|biaik+1|。但这样是O(n3)的时间复杂度,无法通过。先把绝对值拆开,总共有四种:

  1. f[ik][jk]+bik+1ai+biaik+1
  2. f[ik][jk]+aibik+1+biaik+1
  3. f[ik][jk]+bik+1ai+aik+1bi
  4. f[ik][jk]+aibik+1+aik+1bi

同时发现ij都是减k,那么能转移到i,jx,y都满足ij=xy。那么我们可以g[l][t],t{0,1,2,3}表示ij=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 @   maburb  阅读(7)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话
点击右上角即可分享
微信分享提示