专栏文章

题解:P12025 [USACO25OPEN] Sequence Construction S

P12025题解参与者 5已保存评论 4

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
4 条
当前快照
1 份
快照标识符
@mipm8v0m
此快照首次捕获于
2025/12/03 14:18
3 个月前
此快照最后确认于
2025/12/03 14:18
3 个月前
查看原文

题意简述

构造序列使得:
  • 1N1001 \le N \le 100
  • a1+a2++aN=Ma_1 + a_2 + \dots + a_N = M
  • popcount(a1) popcount(a2) popcount(aN)=K\text{popcount}(a_1) \oplus \text{ popcount}(a_2) \oplus \dots \oplus \text{ popcount}(a_N) = K
若无解输出 1-1

基本思路

因为 kk 是一堆东西的异或和,不难想到对 kk 进行二进制分解。
k=5k=5 为例,(5)10=(101)2(5)_{10} = (101)_{2}
对于第一位 11,它由一个 xx 满足 popcount(x)=4\text{popcount}(x) = 4 贡献而来,这个 xx 最小为 241=152^4-1 = 15,故我们将 1515 加入序列,同样的对于最后一位 11,将 211=12^1-1=1 加入序列。
该样例对应的 m=33m=33,减去 151511 后还剩下 1717
我们需要之后的元素 11 的个数异或和为 00
1717 是一个奇数,因为 1122 二进制下都只含一个 11,我们先从中取出一个 11 和一个 22,再取出两个 (m3)÷2(m-3) \div 2
对于一个偶数,直接取两个 n÷2n \div 2 则满足条件。
考虑无解情况,若 mm 在某一步小于了 00,则无解。
若剩余的 mm11,如果当前序列有一个 11,改为 22 可以凑出一组解,否则无解。

AC Code

CPP
#include <bits/stdc++.h>
#define F(i, a, b) for (int i = a; i <= b; ++i)
#define _F(i, a, b) for (int i = a; i >= b; --i)
#define ll long long
using namespace std;
ll rd() {
	ll p = 0, f = 1; char ch = getchar();
	while (ch>'9' || ch<'0') {
		if (ch == '-') f = -1;
		ch = getchar();
	}
	while (ch>='0' && ch<='9') p = p*10+ch-'0', ch = getchar();
	return p * f;
}
ll m, k, a[110], tot = 0;
void Solve() {
	tot = 0;
	m = rd(), k = rd();
	_F(i, 5, 0) {
		if (k & (1<<i)) {
			ll cur = (1<<(1<<i))-1;
			m -= cur, a[++tot] = cur;
			if (m < 0) {
				cout << -1 << '\n';
				return ;
			}
		}
	}
	if (m == 1) {
		if (a[tot] != 1) {
			cout << -1 << '\n';
			return ;
		}
		++a[tot];
	} else if (m % 2 == 0) {
		a[++tot] = m/2, a[++tot] = m/2;
	} else {
		a[++tot] = 1, a[++tot] = 2, a[++tot] = (m-3)/2, a[++tot] = (m-3)/2;
	}
	cout << tot << '\n';
	F(i, 1, tot) cout << a[i] << ' ';
	cout << '\n';
}
int main() {
	ll T = rd(); while (T--) Solve();
	return 0;
}

评论

4 条评论,欢迎与作者交流。

正在加载评论...