CF 1478D. Nezzar and Board
Nezzar and Board
题意
有长度为 \(n\) 的序列 \(a\) ,每次可以选择任意两个数字 \(x, y\) (可以相同),把 \(2 \times x - y\) 写入序列 \(a\) 中(\(x, y\) 不会消失),问进行若干次操作后,能否得出给定数字 \(K\) ?
\(1 \le a_i, K \le 10^{18}\) 。
分析
对于 \(2 \times x - y\) ,可以拆分成 \(x + (x - y)\) ,也就是一个数加上它与另外一个数的差。我们分成几步模拟:
我们假设:
\(x_i = x_j + (x_j - x_k)\)
\(x_a = x_i + (x_i - x_c)\)
\(x_b = x_a + (x_a - x_d)\)
那么我们可以得到 \(x_b = x_j + (x_j - x_k) + (x_i - x_c) + (x_a - x_d)\)
可以得到表达式:
\(x_i + \sum_{j,k}(x_j - x_k) = K\)
其中 \(j, k\) 表示序列中任意元素的下标,甚至 \(x_i\) 也可以换成任意一个 \(x\) ,这个在下文说明。
由于题目明确说明可以选择同一个数字,所以这个表达式不仅可以表示新加进去的数字,也可以表示原有序列中的数字。
所以这个表达式可以表示序列中任意数字。
把表达式变形一下:
\(\sum_{j, k}(x_j - x_k) = K - a_i\) 。
我们可以把 \(x_i\) 换成任意数字,比如 \(x_1\) 换成 \(x_n\) :
- 选择 \(x_1, x_n\) ,加入 \(x_1 + (x_1 - x_n)\) 。
- 选择 \(x_1, x_1 + (x_1 - x_n)\) ,加入 \(x_1 + (x_1 - (x_1 + (x_1 - x_n))) = x_n\) 。
同理我们可以把表达式中 \(x_k\) 换成 \(x_1\) 。
得到最终的方程
令 \(a_i = x_j - x_1\) ,\(y_i\) 表示 \(a_i\) 使用的次数。
那么有
只需要判断这个方程是否有解即可。
贝祖定理:
设 \(a, b\) 是不全为 0 的整数,存在整数 \(x, y\) ,使得 \(ax + by = gcd(a, b)\) 。
对于多个变量也适用:
那么,如果 \(K - x_1\) 是 \(gcd(x1 - x1 = 0, x2 - x1, x3 - x1 ... )\) 的倍数,则此方程有解。
Code
/* 终点是一切概率的结束,也是一切期望的开始 */
#include <bits/stdc++.h>
#define int long long
using namespace std;
void solve ()
{
int n, k, g = 0; cin >> n >> k;
vector<int> a(n);
for (int i = 0; i < n; i ++ ) cin >> a[i], g = __gcd(g, a[i] - a[0]);
if ((k - a[0]) % g) cout << "NO\n"; else cout << "YES\n";
}
signed main ()
{
cout.tie(0)->sync_with_stdio(0);
int _; for (cin >> _; _--; ) solve();
return 0;
}