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\) :

  1. 选择 \(x_1, x_n\) ,加入 \(x_1 + (x_1 - x_n)\)
  2. 选择 \(x_1, x_1 + (x_1 - x_n)\) ,加入 \(x_1 + (x_1 - (x_1 + (x_1 - x_n))) = x_n\)

同理我们可以把表达式中 \(x_k\) 换成 \(x_1\)
得到最终的方程

\[\sum_j(x_j - x_1) = K - x_1 \]

\(a_i = x_j - x_1\)\(y_i\) 表示 \(a_i\) 使用的次数。

那么有

\[y_1a_1 + y_2a_2 + ... + y_na_n = K - x_1 \]

只需要判断这个方程是否有解即可。

贝祖定理:

\(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;
}
posted @ 2021-11-20 15:31  Horb7  阅读(41)  评论(0编辑  收藏  举报