VP Educational Codeforces Round 157 (Rated for Div. 2)


A. Treasure Chest

题意:你要经过y然后到x,你可以让x最多移动k,求最短距离。

如果yx,答案就是x
否则尽量把xy移就行。

点击查看代码
void solve() {
    int x, y, k;
    std::cin >> x >> y >> k;
    if (y <= x) {
    	std::cout << x << "\n";
    } else {
    	std::cout << std::max(y, 2 * (y - x - k) + x + k) << "\n";
    }
}

B. Points and Minimum Distance

题意:把2n个数分成n个坐标,然后按顺序经过每个点,两点之间距离为曼哈顿距离,求距离最短。

单独看一个坐标,我们肯定希望能递增或递减的走,否则走过去一点又走回来肯定走的更多。
那么我们把所有数组排序,因为起点到终点要包含n个点,所以可以选前n个为x坐标,后n个为y坐标,这样总距离为这时距离就相当于是相邻两数之差,就等于ana1+a2nan+1。可以证明这样走的距离最短,因为交换任意位置都会使得距离增加。

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

    std::sort(a.begin(), a.end());
    std::cout << (a[n - 1] - a[0] + a[2 * n - 1] - a[n]) << "\n";
    for (int i = 0; i < n; ++ i) {
    	std::cout << a[i] << " " << a[i + n] << "\n";
    }
}

C. Torn Lucky Ticket

题意:又n个长度小于5的数字,求有多少点对使得si+sj是幸运的,一个数字是幸运的那么它的长度是偶数并且前半部分数字和等于后半部分数字和。si+sj就是两个数字拼接起来。

直接枚举每个数字作为较长的那一部分的贡献,分为在前面时和在后面时。用map统计长度为len总和为s的数字的个数。因为每个数字统计的数长度小于自己,所以先把数字按长度排序。

点击查看代码
void solve() {
    int n;
    std::cin >> n;
    std::vector<std::map<int, int> > cnt(6);
    std::vector<std::string> a(n);

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

    auto get = [&](std::string s) -> int {
    	int res = 0;
    	for (auto & c : s) {
    		res = res + c - '0';
    	}
    	return res;
    };

    std::sort(a.begin(), a.end(), [&](std::string & a, std::string & b) {
    	return a.size() < b.size();
    });

    i64 ans = 0;
    for (int i = 0; i < n; ++ i) {
    	int len = a[i].size();
    	for (int j = len; j > len / 2; -- j) {
    		int x = get(a[i].substr(0, j)), y = get(a[i].substr(j));
    		ans += cnt[j * 2 - len][x - y];
    	}

    	for (int j = len; j > len / 2; -- j) {
    		int x = get(a[i].substr(len - j)), y = get(a[i].substr(0, len - j));
    		ans += cnt[j * 2 - len][x - y];
    	}

    	cnt[len][get(a[i])] += 1;
    }

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

D. XOR Construction

题意:给定一个数组a,你要构造一个b,使得0n1都恰好出现一次,并且ai=bibi+1

bi+1=aibi。列出前i个式子发现bi等于a的前缀异或和异或b1sumi1b1,只要确定b1的值就可以求出b。那么我们枚举b1,看它和这些sum的最大异或和有没有超过n1,只要没超过就合法。因为题目保证有解,所以sumi!=sumj,(i!=j,1<=i,j<n),则不可能有两个相等的b,又因为最大不超过n1,则可以保证恰好每个数出现一次。

点击查看代码
struct TrieWith01 {
	std::vector<std::array<int, 2> > tr;
	int idx;

	int creat() {
		tr.push_back({});
		idx += 1;
		return idx;
	}

	TrieWith01() {
		creat();
		idx = 0;
	}

	void insert(int x) {
		int p = 0;
		for (int i = 30; i >= 0; -- i) {
			int s = x >> i & 1;
			if (!tr[p][s]) {
				tr[p][s] = creat();
			}

			p = tr[p][s];
		}
	}

	int xor_max(int x) {
		int p = 0;
		int res = 0;
		for (int i = 30; i >= 0; -- i) {
			int s = x >> i & 1;
			if (tr[p][!s]) {
				res += 1 << i;
				p = tr[p][!s];
			} else {
				p = tr[p][s];
			}
		}

		return res;
	}
};

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

    TrieWith01 tr;
    int sum = 0;
    for (int i = 0; i + 1 < n; ++ i) {
    	sum ^= a[i];
    	tr.insert(sum);
    }

    std::vector<int> b(n);
    for (int i = 0; i < n; ++ i) {
    	int x = tr.xor_max(i);
    	if (x == n - 1 || (x == n - 2 && i == n - 1)) {
    		b[0] = i;
    		for (int j = 1; j < n; ++ j) {
    			b[j] = b[j - 1] ^ a[j - 1];
    		}
    		break;
    	}
    }

    for (int i = 0; i < n; ++ i) {
    	std::cout << b[i] << " \n"[i == n - 1];
    }
}
posted @   maburb  阅读(5)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示