You are given an array of positive integers a = [ a 0 , a 1 , … , a n − 1 ] a = [a_0, a_1, \dots, a_{n - 1}] a=[a0,a1,…,an−1] ( n ≥ 2 n \ge 2 n≥2).
In one step, the array a a a is replaced with another array of length n n n, in which each element is the greatest common divisor (GCD) of two neighboring elements (the element itself and its right neighbor; consider that the right neighbor of the ( n − 1 ) (n - 1) (n−1)-th element is the 0 0 0-th element).
Formally speaking, a new array b = [ b 0 , b 1 , … , b n − 1 ] b = [b_0, b_1, \dots, b_{n - 1}] b=[b0,b1,…,bn−1] is being built from array a = [ a 0 , a 1 , … , a n − 1 ] a = [a_0, a_1, \dots, a_{n - 1}] a=[a0,a1,…,an−1] such that b i b_i bi = gcd ( a i , a ( i + 1 ) m o d n ) = \gcd(a_i, a_{(i + 1) \mod n}) =gcd(ai,a(i+1)modn), where gcd ( x , y ) \gcd(x, y) gcd(x,y) is the greatest common divisor of x x x and y y y, and x m o d y x \mod y xmody is the remainder of x x x dividing by y y y. In one step the array b b b is built and then the array a a a is replaced with b b b (that is, the assignment a a a := b b b is taking place).
For example, if a = [ 16 , 24 , 10 , 5 ] a = [16, 24, 10, 5] a=[16,24,10,5] then b = [ gcd ( 16 , 24 ) b = [\gcd(16, 24) b=[gcd(16,24), gcd ( 24 , 10 ) \gcd(24, 10) gcd(24,10), gcd ( 10 , 5 ) \gcd(10, 5) gcd(10,5), gcd ( 5 , 16 ) ] \gcd(5, 16)] gcd(5,16)] = [ 8 , 2 , 5 , 1 ] = [8, 2, 5, 1] =[8,2,5,1]. Thus, after one step the array a = [ 16 , 24 , 10 , 5 ] a = [16, 24, 10, 5] a=[16,24,10,5] will be equal to [ 8 , 2 , 5 , 1 ] [8, 2, 5, 1] [8,2,5,1].
For a given array a a a, find the minimum number of steps after which all values a i a_i ai become equal (that is, a 0 = a 1 = ⋯ = a n − 1 a_0 = a_1 = \dots = a_{n - 1} a0=a1=⋯=an−1). If the original array a a a consists of identical elements then consider the number of steps is equal to 0 0 0.
The first line contains an integer t t t ( 1 ≤ t ≤ 1 0 4 1 \le t \le 10^4 1≤t≤104). Then t t t test cases follow.
Each test case contains two lines. The first line contains an integer n n n ( 2 ≤ n ≤ 2 ⋅ 1 0 5 2 \le n \le 2 \cdot 10^5 2≤n≤2⋅105) — length of the sequence a a a. The second line contains n n n integers a 0 , a 1 , … , a n − 1 a_0, a_1, \dots, a_{n - 1} a0,a1,…,an−1 ( 1 ≤ a i ≤ 1 0 6 1 \le a_i \le 10^6 1≤ai≤106).
It is guaranteed that the sum of n n n over all test cases doesn’t exceed 2 ⋅ 1 0 5 2 \cdot 10^5 2⋅105.
Print t t t numbers — answers for each test case.
5
4
16 24 10 5
4
42 42 42 42
3
4 6 4
5
1 2 3 4 5
6
9 9 27 9 9 63
3
0
2
1
1
给你一个由正整数 a = [ a 0 , a 1 , … , a n − 1 ] a = [a_0, a_1, \dots, a_{n - 1}] a=[a0,a1,…,an−1] ( n ≥ 2 n \ge 2 n≥2 ) 组成的数组。
在一个步骤中,数组 a a a 被另一个长度为 n n n 的数组取代,其中每个元素都是两个相邻元素(元素本身及其右邻;考虑到 ( n − 1 ) (n - 1) (n−1) /th 元素的右邻是 0 0 0 /th 元素)的 最大公约数 (GCD)。
从形式上来说,一个新的数组 b = [ b 0 , b 1 , … , b n − 1 ] b = [b_0, b_1, \dots, b_{n - 1}] b=[b0,b1,…,bn−1] 是由数组 a = [ a 0 , a 1 , … , a n − 1 ] a = [a_0, a_1, \dots, a_{n - 1}] a=[a0,a1,…,an−1] 建立的,其中 b i b_i bi 为 = gcd ( a i , a ( i + 1 ) m o d n ) = \gcd(a_i, a_{(i + 1) \mod n}) =gcd(ai,a(i+1)modn) , gcd ( x , y ) \gcd(x, y) gcd(x,y) 为 x x x , y y y 为 x m o d y x \mod y xmody 。 = gcd ( a i , a ( i + 1 ) m o d n ) = \gcd(a_i, a_{(i + 1) \mod n}) =gcd(ai,a(i+1)modn) ,其中 gcd ( x , y ) \gcd(x, y) gcd(x,y) 是 x x x 和 y y y 的最大公约数,而 x m o d y x \mod y xmody 是 x x x 除以 y y y 的余数。一步建立数组 b b b ,然后用 b b b 替换数组 a a a (即赋值 a a a 除以 b b b 的余数)。(即赋值 a a a := b b b )。
例如,如果是 a = [ 16 , 24 , 10 , 5 ] a = [16, 24, 10, 5] a=[16,24,10,5] 则是 b = [ gcd ( 16 , 24 ) b = [\gcd(16, 24) b=[gcd(16,24) , gcd ( 24 , 10 ) \gcd(24, 10) gcd(24,10) , gcd ( 10 , 5 ) \gcd(10, 5) gcd(10,5) , gcd ( 5 , 16 ) ] \gcd(5, 16)] gcd(5,16)] . = [ 8 , 2 , 5 , 1 ] = [8, 2, 5, 1] =[8,2,5,1] .这样,经过一步后,数组 a = [ 16 , 24 , 10 , 5 ] a = [16, 24, 10, 5] a=[16,24,10,5] 将等于 [ 8 , 2 , 5 , 1 ] [8, 2, 5, 1] [8,2,5,1] 。
对于给定的数组 a a a ,求所有值 a i a_i ai 都相等(即 a 0 = a 1 = ⋯ = a n − 1 a_0 = a_1 = \dots = a_{n - 1} a0=a1=⋯=an−1 )的最小步数。如果原数组 a a a 由完全相同的元素组成,则考虑步数等于 0 0 0 。
第一行包含一个整数 t t t ( 1 ≤ t ≤ 1 0 4 1 \le t \le 10^4 1≤t≤104 )。然后是 t t t 个测试用例。
每个测试用例包含两行。第一行包含一个整数 n n n ( 2 ≤ n ≤ 2 ⋅ 1 0 5 2 \le n \le 2 \cdot 10^5 2≤n≤2⋅105 ) - 序列长度 a a a 。第二行包含 n n n 个整数 a 0 , a 1 , … , a n − 1 a_0, a_1, \dots, a_{n - 1} a0,a1,…,an−1 ( 1 ≤ a i ≤ 1 0 6 1 \le a_i \le 10^6 1≤ai≤106 )。( 1 ≤ a i ≤ 1 0 6 1 \le a_i \le 10^6 1≤ai≤106 ).
保证所有测试用例的 n n n 之和不超过 2 ⋅ 1 0 5 2 \cdot 10^5 2⋅105 。
打印 t t t 个数字 - 每个测试用例的答案。
ST表:
由题意可知,经过 k k k 次变化后 :
a 1 = gcd ( a 1 , a 2 … … a k + 1 m o d n ) a_1=\gcd(a_1,a_2……a_{k+1 \mod n}) a1=gcd(a1,a2……ak+1modn)
a 2 = gcd ( a 2 , a 3 … … a k + 2 m o d n ) a_2=\gcd(a_2,a_3……a_{k+2 \mod n}) a2=gcd(a2,a3……ak+2modn)
… \dots …
a i = gcd ( a i , a i + 1 … … a k + i m o d n ) a_i=\gcd(a_i,a_{i+1}……a_{k+i \mod n}) ai=gcd(ai,ai+1……ak+imodn)
所以可以将问题转化为:求一个最小的 k k k 使得 a a a 中每一个长度大于 k k k 的区间的 gcd \gcd gcd 为 gcd ( a 1 , a 2 , . . . , a n ) \gcd(a_1,a_2,...,a_n) gcd(a1,a2,...,an)。
可以发现, k k k 具有单调性。因为若 k k k 满足题意,则比 k k k 大也必定满足题意,因为 gcd ( a , a ) = a \gcd(a,a)=a gcd(a,a)=a。所以我们考虑二分答案:每次二分出一个 k k k,求出 a a a 中每个长度为 k k k 的序列的 gcd \gcd gcd,比较是否相等。
现在我们就需要一个快速的算法求 a 中一段子序列的 gcd,所以考虑 ST表。因为 gcd ( gcd ( a , b ) , gcd ( a , c ) ) = gcd ( a , b , c ) \gcd(\gcd(a,b),\gcd(a,c))=\gcd(a,b,c) gcd(gcd(a,b),gcd(a,c))=gcd(a,b,c)。
时间复杂度: O ( n × log 2 n ) O(n\times \log^{2} n) O(n×log2n)。
#include
using namespace std;
#define int long long
const int Maxn = 2e5 + 10;
int n, a[Maxn];
int lg2[Maxn], ST[Maxn][40];
int ans;
inline void init();
inline void solve();
inline int Binary_search(int n);
inline bool check(int k);
inline int ask(int l, int r);
inline void work() {
init();
int T;
cin >> T;
while (T--) {
solve();
}
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
work();
return 0;
}
inline void init() {
for (int i = 2; i < Maxn; i++) {
lg2[i] = lg2[i >> 1] + 1;
}
}
inline void solve() {
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> a[i];
ST[i][0] = a[i];
}
for (int j = 1; j <= lg2[n]; j++) {
for (int i = 1; i <= (n) - (1 << j) + 1; i++) {
ST[i][j] = __gcd(ST[i][j - 1], ST[i + (1 << j - 1)][j - 1]);
}
}
ans = Binary_search(n);
cout << ans << endl;
}
inline int Binary_search(int n) {
int l = 1, r = n, mid;
while (l < r) {
mid = l + r >> 1;
if (check(mid)) {
r = mid;
} else {
l = mid + 1;
}
}
return l - 1;
}
inline int ask(int l, int r) {
if (l <= n && r > n) {
return __gcd(ask(l, n), ask(1, r - n));
}
int k = lg2[r - l + 1];
return __gcd(ST[l][k], ST[r - (1 << k) + 1][k]);
}
inline bool check(int k) {
int t = ask(1, 1 + k - 1);
for (int i = 2; i <= n; i++) {
if (ask(i, i + k - 1) != t) {
return 0;
}
}
return 1;
}
汗流浃背了吧。