赞
踩
http://codeforces.com/contest/1478/problem/D
给一个数列, a 1 a_1 a1, a 2 a_2 a2, a 3 a_3 a3… a n a_n an , 每一次操作定义为,从已有的数字中随意选一个数字作为x,再选一个数字作为y,两个数字可以相同,然后向数列中加入2*x - y 这个数字,选中的数字仍然在数列中。
可以操作任意次,问是否能凑出k。
首先考虑最终组成的表达式的形式,当只进行一次操作时,结果一定是 2 ∗ x − y 2*x- y 2∗x−y这样的形式,当进行两次操作,那么一定是 2 ∗ ( 2 ∗ x − y ) − ( 2 ∗ p − q ) 2 *(2*x - y) - (2 * p -q ) 2∗(2∗x−y)−(2∗p−q) 这样的形式,所以观察系数和可以发现,系数和最终一定是 2 * (1) - 1 这样的形式,由于每次都会得到一个系数和为1的表达式,所以最终的表达式系数和一定为1.反过来想也就是,用这个方法可以凑出所有系数为1的表达式。
然后怎么才能凑出所有系数为1的表达式呢,也就是凑出所有系数为0的表达式然后再随便加一个数字即可,所以我们需要所有的 a i − a j a_i - a_j ai−aj 进行组合,这样就可以凑出所有系数为0的表达式,但是组合方式是 n 2 n^2 n2的,我们又可以通过把每个值变成 a i − a i − 1 a_i - a_{i-1} ai−ai−1的形式,这样我们就能通过n - 1个表达式之间的运算凑出 n 2 n^2 n2种系数为0的 a i − a j a_i - a_j ai−aj形式的表达。
最终,我们就得到了n-1 个值,我们要看这n - 1个值通过任意组合能否得到一个等于 k - a i a_i ai 这样的值。这就是裴蜀定理。
所以我们只需要算出n-1个数的gcd,看下是不是 k − a [ i ] ( 1 ≤ i ≤ n ) k - a[i](1 \le i \le n) k−a[i](1≤i≤n)的因子即可。
#include <random> #include <bits/stdc++.h> using namespace std; const int maxn = 2e5+10; long long a[maxn]; int main() { int t; cin >> t; while(t--) { int n; long long k; cin >> n >> k; long long gcd = 0; map<long long,int> mp; cin >> a[1]; mp[a[1]] = 1; for (int i = 2; i <= n; i++) { cin >> a[i]; mp[a[i]] = 1; gcd = __gcd(gcd, (a[i]-a[i-1])); } int flag = 0; for (int i = 1; i <= n; i++) { if ((k - a[i]) % gcd ==0) { flag = 1; } } if (flag) { printf("YES\n"); } else { printf("NO\n"); } } return 0; }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。