### felix-felicis's blog

By felix-felicis, history, 3 years ago,

Problem: Integers have friends.

After seeing the tutorial of this problem, I learnt about the sparse table. The tutorial though provides the method which is sparse table construction and then using binary search, I could not completely understand it. The comment section was pretty helpful but now the older comment section has been deleted. Can someone please explain what they have done( preferably an approach using sparse table because I have spent a lot of time learning it.)

If possible, please explain it in a beginner-friendly manner as I have never used a sparse table till now. It would really be helpful to me...

• 0

| Write comment?
 » 3 years ago, # | ← Rev. 9 →   0 Part 1 (Why GCD?):Firstly, let's find the answer for a fixed array (not subarray). How can we do that? Let's use the fact that $(x + m * y) \mod m = x \mod m$ for every $x$, $y$ and $m$. Every difference of two numbers must be divisible by $m$ because $y$ must be an integer. What's the biggest number that divides every $a_i$? It's just their GCD! $m$ can't be equals to $1$ according to the statement, so now the problem is to find the longest subarray with GCD > 1.Part 2 (Solving for every subarray efficiently):Let's build GCD sparse table on differences of $a$. If you're familiar with two pointers technique (if not, there's a very nice lesson in EDU!), you will easily come up with such solution: Let's maintain two pointers — $L = 0$ and $R = 0$. While $R < n$:2.1. While $GCDQuery(L, R) = 1$ increase L by 1. Corner case: $a_i = 1$. Stop the movement of $L$ pointer when $L = R$.2.2. If $GCDQuery(L, R) > 1$, then do $ans = max(ans, R - L + 2)$. Why am I using $R - L + 2$ instead of $R - L + 1$? That's because the number of differences in $a$ equals to $n - 1$. Print $m$. Implementation: Codeint my_gcd(int a, int b) { return (a == 0ll ? b : gcd(b % a, a)); } int st[200000][20]; void build(vector b) { for(int i = 0; i < len(b); i++) st[i][0] = b[i]; for(int j = 1; j < 20; j++) { for(int i = 0; i + (1 << j) <= len(b); i++) { st[i][j] = my_gcd(st[i][j - 1], st[i + (1 << (j - 1))][j - 1]); } } } int query(int l, int r) { return my_gcd(st[l][log(r - l + 1)], st[r - (1 << log(r - l + 1)) + 1][log(r - l + 1)]); } void test_case() { int n; cin >> n; vector a(n); cin >> a; vector b(n - 1); for(int i = 1; i < n; i++) b[i - 1] = abs(a[i] - a[i - 1]); debug(b); build(b); int ans = 1; for(int L = 0, R = 0; R < n - 1; R++) { while(L < R && query(L, R) == 1) L++; if(query(L, R) != 1) ans = max(ans, R - L + 2); } cout << ans << "\n"; } 
•  » » 3 years ago, # ^ |   +1 Thanks bro. This is really cool...:)