给定一个长度为 n n n的序列, 可以执行任意多次操作: 给所有位置的数值+1.
问: 最少执行多少次操作, 使得 g c d ( { a 1 , a 2 , . . . , a n } ) ≠ 1 gcd(\{ a_1, a_2, ..., a_n \}) \ne 1 gcd({a1,a2,...,an})=1. 若无解则输出 − 1 -1 −1.
差分
这类区间加 且 求 g c d gcd gcd的题目, 我们比较容易的想到转化成差分的思路进行求解.
对于本题而言, 每次是使区间 [ 1 , n ] + 1 [1, n] + 1 [1,n]+1. 若设原序列为 a [ ] a[] a[], 差分序列为 b [ ] b[] b[]. 则操作等价于使得 b [ 1 ] + 1 , b [ n + 1 ] − 1 b[1] + 1, b[n + 1] - 1 b[1]+1,b[n+1]−1. 对 n + 1 n + 1 n+1位置操作没有意义, 因此操作最终等价于: b[1] + 1
.
现在问题变为, 至少进行多少次b[1] + 1
操作, 使得 g c d ( { b 1 , b 2 , . . . , b n } ) ≠ 1 gcd(\{ b_1, b_2, ..., b_n \}) \ne 1 gcd({b1,b2,...,bn})=1.
我们易得: 如果 g c d ( { b 2 , b 3 , . . . , b n } ) = 1 gcd(\{b_2, b_3, ..., b_n\}) = 1 gcd({b2,b3,...,bn})=1, 则无解.
质因数分解
反之, 设 d = g c d ( { b 2 , b 3 , . . . , b n } ) d = gcd(\{b_2, b_3, ..., b_n\}) d=gcd({b2,b3,...,bn}). 相当于我们需要求 g c d ( b 1 , d ) ≠ 1 gcd(b_1, d) \ne 1 gcd(b1,d)=1的最小操作次数.
我们只需要让 b 1 b_1 b1和 d d d有至少1个相同的质因子即可.
因此我们可以对 d d d进行质因数分解, 通过枚举所有结果, 取最小值即可.
#include
#define rep(i, n) for (int i = 1; i <= (n); ++i)
using namespace std;
typedef long long ll;
const int N = 1E5 + 10;
int a[N], b[N];
int get(int d) { return (d - b[1] % d) % d; }
int fact(int d) {
int res = INT_MAX;
for (int i = 2; i <= d / i; ++i) {
if (d % i == 0) {
res = min(res, get(i));
while (d % i == 0) d /= i;
}
}
if (d > 1) res = min(res, get(d));
return res;
}
int main()
{
int t; cin >> t;
rep(tt, t) {
int n; scanf("%d", &n);
rep(i, n) scanf("%d", &a[i]), b[i] = abs(a[i] - a[i - 1]);
int d = 0;
for (int i = 2; i <= n; ++i) d = gcd(d, b[i]);
if (d == 0) printf("Case %d: %d\n", tt, b[1] == 1);
else {
int res = fact(d);
printf("Case %d: %d\n", tt, res == INT_MAX ? -1 : res);
}
}
return 0;
}