VP Educational Codeforces Round 6


A. Professor GukiZ's Robot

题意:给你两个坐标,可以走八个方向,求从第一个坐标到第二个坐标的最少操作数。

先斜着走,然后到了某个坐标相同的位置就直着走,那么方向就是两个坐标的最远距离。

点击查看代码
void solve() {
	int x1, y1, x2, y2;
	std::cin >> x1 >> y1 >> x2 >> y2;
	int a = std::abs(x1 - x2), b = std::abs(y1 - y2);
	std::cout << std::max(a, b) << "\n";
}

B. Grandfather Dovlet’s calculator

题意:1到9的数字有一个值,求一个区间的数字值之和。

点击查看代码
void solve() {
    const int N = 1e6 + 5;
    std::vector<int> sum(N);
    sum[0] = 6; sum[1] = 2; sum[2] = 5; sum[3] = 5; sum[4] = 4; sum[5] = 5; sum[6] = 6;
    sum[7] = 3; sum[8] = 7; sum[9] = 6;
    for (int i = 10; i <= 1e6; ++ i) {
    	int tot = 0;
    	int x = i;
    	do {
    		tot += sum[x % 10];
    		x /= 10;
    	} while (x);

    	sum[i] = tot;
    }

    int a, b;
    std::cin >> a >> b;
    i64 ans = 0;
    for (int i = a; i <= b; ++ i) {
    	ans += sum[i];
    }
    std::cout << ans << "\n";
}

C. Pearls in a Row

题意:给你一个数组,你要把它分成最多的块,使得每个块内至少有一个数出现两次以上。

记每个位置上数字出现的下一个位置,然后贪心的取连续一段使得最右边的数字恰好出现两次就行。

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

    std::map<int, int> pos;
    std::vector<int> next(n, n);
    for (int i = n - 1; i >= 0; -- i) {
    	if (pos.count(a[i])) {
    		next[i] = pos[a[i]];
    	}

    	pos[a[i]] = i;
    }

    std::vector<std::pair<int, int>> ans;
    for (int i = 0; i < n; ++ i) {
    	int j = i, r = next[i];
    	while (j < r) {
    		r = std::min(r, next[j]);
    		++ j;
    	}

    	if (r == n) {
    		if (ans.empty()) {
    			std::cout << -1 << "\n";
	    		return;
    		} else {
    			ans.back().second = n - 1;
    			break;
    		}
    	}

    	ans.push_back({i, j});
    	i = j;
    }

    std::cout << ans.size() << "\n";
    for (auto & [l, r] : ans) {
    	std::cout << l + 1 << " " << r + 1 << "\n";
    }
}

D. Professor GukiZ and Two Arrays

这题调红温了,思路是对的但一直wa。

题意:给你两个数组,你可以交换两个数组的数,不超过两个,使得两个数组和的差的绝对值最小。

交换一对i,j得到suma(ai+bj)(sumb(bj+ai))=sumasumb2×ai+2×bj
交换两对(i,j),(x,y),则答案为sumasumb2×ai2×ax+2×bj+2×by
对于第二种情况,把所有2×(ai+aj)存下来和使用2×(bi+bj)存下来。然后枚举每个ai+aj二分找sumasumb2×(ai+aj)的两个bi,bj,取最小值就行了。

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

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

    i64 suma = std::accumulate(a.begin(), a.end(), 0ll);
    i64 sumb = std::accumulate(b.begin(), b.end(), 0ll);
	
	std::vector<std::array<i64, 3>> A, B;
	for (int i = 0; i < n; ++ i) {
		for (int j = i + 1; j < n; ++ j) {
			A.push_back({2 * (a[i] + a[j]), i, j});
		}
	} 

	for (int i = 0; i < m; ++ i) {
		for (int j = i + 1; j < m; ++ j) {
			B.push_back({2 * (b[i] + b[j]), i, j});
		}
	}

	std::sort(A.begin(), A.end());
	std::sort(B.begin(), B.end());

	i64 ans2 = 1e18;
	std::vector<std::pair<int, int>> op2;
	for (auto & [x, i, j] : A) {
		i64 v = suma - sumb - x;
		if (v <= 0) {
			int p = std::lower_bound(B.begin(), B.end(), std::array<i64, 3>{std::abs(v), 0, 0}) - B.begin();
			if (p != B.size()) {
				if (std::abs(suma - sumb - x + B[p][0]) < ans2) {
					ans2 = std::abs(suma - sumb - x + B[p][0]);
					op2.clear();
					op2.push_back({i, B[p][1]}); 
					op2.push_back({j, B[p][2]}); 
				}
			}	

			if (p != 0) {
				-- p;
				if (std::abs(suma - sumb - x + B[p][0]) < ans2) {
					ans2 = std::abs(suma - sumb - x + B[p][0]);
					op2.clear();
					op2.push_back({i, B[p][1]}); 
					op2.push_back({j, B[p][2]}); 
				}
			}	
		} else {
			int l = 0, r = (int)B.size() - 1;
			while (l < r) {
				int mid = l + r + 1 >> 1;
				if (-B[mid][0] >= v) {
					l = mid;
				} else {
					r = mid - 1;
				}
			}

			int p = l;
			if (p >= 0 && p <= (int)B.size() - 1 && std::abs(suma - sumb - x + B[p][0]) < ans2) {
				ans2 = std::abs(suma - sumb - x + B[p][0]);
				op2.clear();
				op2.push_back({i, B[p][1]}); 
				op2.push_back({j, B[p][2]}); 
			}

			if (p < (int)B.size() - 1) {
				++ p;
				if (p >= 0 && std::abs(suma - sumb - x + B[p][0]) < ans2) {
					ans2 = std::abs(suma - sumb - x + B[p][0]);
					op2.clear();
					op2.push_back({i, B[p][1]}); 
					op2.push_back({j, B[p][2]}); 
				}
			}
		}
	}

	i64 ans1 = 1e18;
	std::pair<int, int> op1;
	for (int i = 0; i < n; ++ i) {
		for (int j = 0; j < m; ++ j) {
			if (std::abs(suma - sumb - 2 * a[i] + 2 * b[j]) < ans1) {
				ans1 = std::abs(suma - sumb - 2 * a[i] + 2 * b[j]);
				op1 = {i, j};
			}
		}
	}

	i64 ans0 = std::abs(suma - sumb);
	if (ans0 <= ans1 && ans0 <= ans2) {
		std::cout << ans0 << "\n";
		std::cout << 0 << "\n";
	} else if (ans1 <= ans2 && ans1 <= ans0) {
		std::cout << ans1 << "\n";
		std::cout << 1 << "\n";
		std::cout << op1.first + 1 << " " << op1.second + 1 << "\n";
	} else {
		std::cout << ans2 << "\n";
		std::cout << 2 << "\n";
		for (auto & [x, y] : op2) {
			std::cout << x + 1 << " " << y + 1 << "\n";
		}
	}
}

E. New Year Tree

题意:给你一棵树,每个节点有一个颜色,有两种操作,问一棵子树的节点有多少不同的颜色,或者把一棵子树染成同一种颜色。

观察到颜色数很少,可以用线段树维护dfs序,那么一棵子树就是一段区间,颜色可以用一个longlong类型存,或者用bitset。

点击查看代码
#define ls (u << 1)
#define rs (u << 1 | 1)
#define umid (tr[u].l + tr[u].r >> 1)

template <class Info, class Tag>
struct Node {
	int l, r;
	Info info;
	Tag tag;
};

template <class Info, class Tag>
struct SegmentTreeWithLazy {
	std::vector<Node<Info, Tag> > tr;
	SegmentTreeWithLazy(int _n) {
		init(_n);
	}

	SegmentTreeWithLazy(int _n, std::vector<Info> & a) {
		init(_n, a);
	}

	void init(int _n) {
		tr.assign(_n << 2, {});
		build(1, _n);
	}

	void init(int _n, std::vector<Info> & a) {
		tr.assign(_n << 2, {});
		build(1, _n, a);
	}

	void pushup(int u) {
		tr[u].info = tr[ls].info + tr[rs].info;
	}

	void pushdown(Node<Info, Tag> & u, Tag tag) {
		u.info = u.info + tag;
		u.tag = u.tag + tag;
	}

	void pushdown(int u) {
		if (tr[u].tag.exist()) {
			pushdown(tr[ls], tr[u].tag);
			pushdown(tr[rs], tr[u].tag);
			tr[u].tag.clear();
		}
	}

	void build(int l, int r, int u = 1) {
		tr[u] = {l, r, {}};
		if (l == r) {
			return;
		}

		int mid = l + r >> 1;
		build(l, mid, ls); build(mid + 1, r, rs);
	}

	void build(int l, int r, std::vector<Info> & a, int u = 1) {
		tr[u] = {l, r, {}};
		if (l == r) {
			tr[u].info = a[l];
			return;
		}

		int mid = l + r >> 1;
		build(l, mid, a, ls); build(mid + 1, r, a, rs);
		pushup(u);
	}

	void modify(int l, int r, Tag tag, int u = 1) {
		if (l <= tr[u].l && tr[u].r <= r) {
			pushdown(tr[u], tag);
			return;
		}

		pushdown(u);
		int mid = umid;
		if (l <= mid) {
			modify(l, r, tag, ls);
		}

		if (r > mid) {
			modify(l, r, tag, rs);
		}

		pushup(u);
	}

	Info query(int l, int r, int u = 1) {
		if (l <= tr[u].l && tr[u].r <= r) {
			return tr[u].info;
		}

		pushdown(u);

		int mid = umid;
		if (r <= mid) {
			return query(l, r, ls);
		}  else if (l > mid) {
			return query(l, r, rs);
		}

		return query(l, r, ls) + query(l, r, rs);
	}
};

const int N = 61;

struct Info {
	std::bitset<N> s;
};

struct Tag {
	int c;

	bool exist() {
		return c != 0;
	}

	void clear() {
		c = 0;
	}
};

Info operator + (Info a, Info b) {
	a.s |= b.s;
	return a;
}

Info operator + (Info a, Tag b) {
	std::bitset<N> s;
	s[b.c] = 1;
	return {s};
}

Tag operator + (Tag a, Tag b) {
	return b;
}

void solve() {
    int n, m;
    std::cin >> n >> m;
    std::vector<int> a(n + 1);
    for (int i = 1; i <= n; ++ i) {
    	std::cin >> a[i];
    }

    std::vector<std::vector<int>> adj(n + 1);
    for (int i = 1; i < n; ++ i) {
    	int u, v;
    	std::cin >> u >> v;
    	adj[u].push_back(v);
    	adj[v].push_back(u);
    }

    std::vector<int> l(n + 1), r(n + 1);
    int dfn = 0;
    auto dfs = [&](auto self, int u, int fa) -> void {
    	l[u] = ++ dfn;
    	for (auto & v : adj[u]) {
    		if (v == fa) {
    			continue;
    		}

    		self(self, v, u);
    	}

    	r[u] = ++ dfn;
    };

    dfs(dfs, 1, 0);

    SegmentTreeWithLazy<Info, Tag> tr(dfn + 1);
    for (int i = 1; i <= n; ++ i) {
    	tr.modify(l[i], l[i], Tag{a[i]});
    	tr.modify(r[i], r[i], Tag{a[i]});
    }	

    while (m -- ) {
    	int op, v, x;
    	std::cin >> op >> v;
    	if (op == 1) {
    		std::cin >> x;
    		tr.modify(l[v], r[v], Tag{x});
    	} else {
    		std::cout << tr.query(l[v], r[v]).s.count() << "\n";
    	}
    }
}

F. Xors on Segments

题意:定义f(l,r)[l,r]区间内所有数的异或和。给你一个数组,每次求一个区间内任意两个i,j,f(ai,aj)的最大值。

考虑暴力怎么做,就是每次两次循环枚举i,j就行了,但这样会超时,发现我们实际是对于i[l,r]的最大f(ai,aj),j[i+1,r]的所有i的最大值,那么可以考虑预处理,记f[i][j]为从i开始的maxj=ijf(ai,aj),那么f[i][j]=max(f[i][j1],f(ai,aj)),则对于每个i[li,ri]的询问,可以更新拿f[ri]来更新答案。发现转移方程只和当前维有关,可以用滚动数组优化。

点击查看代码
void solve() {
    int n, m;
    std::cin >> n >> m;
    const int N = 1e6 + 5;
    std::vector<int> sum(N);
    for (int i = 1; i < N; ++ i) {
    	sum[i] = sum[i - 1] ^ i;
    }

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

    std::vector<int> l(m), r(m), ans(m);
    for (int i = 0; i < m; ++ i) {
    	std::cin >> l[i] >> r[i];
    }
    
    std::vector<int> f(n + 1);
    for (int i = 1; i <= n; ++ i) {
    	f[i] = a[i];
    	for (int j = i + 1; j <= n; ++ j) {
    		f[j] = std::max(f[j - 1], sum[std::max(a[i], a[j])] ^ sum[std::min(a[i], a[j]) - 1]);
    	}

    	for (int j = 0; j < m; ++ j) {
    		if (i >= l[j] && i <= r[j]) {
    			ans[j] = std::max(ans[j], f[r[j]]);
    		}
    	}
    }

    for (int i = 0; i < m; ++ i) {
    	std::cout << ans[i] << "\n";
    }
}
posted @   maburb  阅读(5)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示