CF 1552D. Array Differentiation
Array Differentiation
题意
给定长度为 \(n\) 的序列 \(a\) ,问是否存在一个长度为 \(n\) 的序列,满足:
- 对于任意 \(1 \le i \le n\),存在 \(1 \le j, k \le n\) ,满足 \(a_i = b_j - b_k\) 。
其中 \(1 \le n \le 10\)。
分析
把 \(b_i\) 当作点权, \(a_i\) 当作边权,对于 \(a_i = b_j - b_k\) ,\(b_j\) 向 \(b_k\) 连一条边。
在 \(n\) 个点内,我们可以构造使得 \(a\) 序列前 \(n-1\) 个数字被满足,比如令 \(b_{i+1} - b_i = a_i\),
这样就形成了一个链。那么,对于剩下一个元素,我们想让它也满足,那么必然会形成一个环。
对于首尾相连的环, \((b_{i+1} - b_i) + (b_i - b_{i-1}) + ... + (b_2 - b_1) + (b_1 - b_{i+1}) = 0\) ,而 \(a_i = b_{i+1} - b_i\),也就是这个环上所有边权相加为 \(0\) 。但是原始环在有方向时不一定是环,所以要重排方向,这样每个边权都可能有两种状态。
所以我们只需要找出是否存在这样的环即可,对于每个点,都有三种状态:
- 不在环内。
- 在环中,重排后为正数。
- 在环中,重排后为负数。
用三进制数判断每个点的状态。
Code
#include <bits/stdc++.h>
using namespace std;
void solve ()
{
int n, m = 1; cin >> n;
vector<int> a(n); forr(&x, a) cin >> x, m *= 3;
for (int i = 1; i < m; i ++ )
{
int s = i, sum = 0;
for (int j = 0; j < n; j ++ )
{
if (s % 3 == 1) sum += a[j];
else if (s % 3 == 2) sum -= a[j];
s /= 3;
}
if (!sum) return cout << "YES\n", void();
}
cout << "NO\n";
}
signed main ()
{
cout.tie(0)->sync_with_stdio(0);
int _; for (cin >> _; _--; ) solve();
return 0;
}