题意
给你设置好长度为n,这 n 个数加起来的和为 m,让你创造一个数组a; 还需要满足条件:在数组a中 任何小于 ai 的之前的数 异或和 为0
空序列的异或和为 0
题解
异或:不相同的时候为 1 ; 0^0 = 0, 1^1 = 0, 1^ 0 = 1, 0^1 = 1;
首先我们很容易想到一种使异或和为0的简单方法:偶数个相同的数进行异或,所以 一种方法就出来了:
当 n 为奇数的时候,n-1一定是偶数,这时候我们就维护前 n - 1 个数都为 1,然后第 n 个数字 就维护为 m - (n-1) 即可。这时候即满足 n 个数,也满足和为 m。
n 无非奇数或者偶数,讨论完 n 为奇数接下来就讨论n 为偶数:
我们·的思路大概还是凑出偶数个相同的数,这样异或和就是0
n 为 偶数的时候,m又分为两种情况:1.m 为偶数,2. m为奇数
-
m为偶数的时候,此时 n 和 m都为偶数:
很容易一种想法:将m均分为n份,这样就是 m / n 个相同的数了,他们只有一个空序列 ,而空序列的异或和为 0;
但是这种是错误的,简单的例子 m = 6,n = 4 是不能整除的
最后的数组之和不是 m。
既然这种不行,但是我们可以发现 n 是个偶数,我们可以设一个x,肯定有 n = 2 + x;而且此时的 x 一定是个偶数,2也是偶数
这样就分成了 x 个相等的数 加上 2个相等的数了,偶数个相同的数异或和一定是 0,这时候只用满足 分出的这些数之和是 m即可
很简单的方法,我们先分出 x 个 1 , 再分出来两个 (m - x) / 2即可。
-
m为奇数的时候,此时 m 为奇数,n 为偶数
这个显然是不成立的,从 1 就可以看出,分出来 x 个 1 后,还有 2 个数,这两个数的和要是 奇数,因为 偶数+奇数才是奇数
所以一个数为偶数,一个数为偶数。两个数肯定是不一样的,异或和的序列肯定不是 0。
最后一种是最简单的,如果n大于m显然是不成立的,因为所有的ai>=1,如过n大于m ,数组和一定大于 m。
代码
#include<iostream>
using namespace std;
const int N = 1e5 + 5;
int t, n, m;
void init() {
cin >> n >> m;
}
void solve() {
// 三种情况
// 1. n 大于 m 一定不成立
if (n > m) {
cout << "NO" << endl;
return ;
}
// 2. n 为奇数:偶数个 1 加上 m - (n-1)
if (n & 1) {
cout << "YES" << endl;
for (int i = 1; i <= n - 1; ++i) cout << "1 ";
cout << m - n + 1 << endl;
return ;
}
// 3. n 为偶数: 又分为两种情况
// i. n 和 m 都为偶数时,
if (!(n & 1) && !(m & 1)) {
cout << "YES" << endl;
int ans = (m - n + 2) >> 1;
for (int i = 1; i <= n - 2; i++) cout << "1 ";
cout << ans << " ";
cout << ans;
cout << endl;
return ;
}
// ii. m 为奇数, 一定不成立
// m如果为奇数,则n为偶数的时候,一定不成立
if ( !(n & 1) && (m & 1)) {
cout << "NO" << endl;
return ;
}
}
int main() {
std::ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> t;
while (t--) {
init();
solve();
}
return 0;
}