[Codeforces] Codeforces Round #736 (Div. 2) D. Integers Have Friends | ST表、二分

196 阅读1分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 1 天,点击查看活动详情

[Codeforces] Codeforces Round #736 (Div. 2) D. Integers Have Friends | ST表、二分

题目链接

codeforces.com/contest/154…

题目

BZ~(VM5K1$F08~29VP3Z8AD.png

题目大意

给长为n的数组a,n个数两两不同,要找最长的区间[l, r]使得存在m >1, a[i] % m (l <= i <= r)全相等

数据范围:

测试样例组数t (1 <= t <= 2e4)

每组输入: n (1 <= n <= 2e5), 1 <= a[i] <= 1e18

限制:所有样例的n之和 <= 2e5

思路

对于a[i] % m = a[j] % m, 我们等价为 m | (a[i] - a[j]), 也就是,m必须是a[i] - a[j]的因子

对于一段区间[l, r] , a[i] % m (l <= i <= r)全相等

等价于,对于[l, r) 满足 m | a[i+1]-a[i]

等价于,m | gcd(a[l+1]-a[l], ... , a[r] - a[r-1])

题目还要求 m > 1

所以我们考虑对a数组做差分, 然后要能对差分数组b快速求区间gcd

显然,st表可以做到这一点,O(nlogn)的初始化和O(1)的查询

然后,我们考虑对枚举差分数组b起点i (1 <= i < n), 二分出最大的右端点j, 满足 gcd(a[i], ..., a[j]) > 1

对于每个起点得到的区间长度+1取max就是最终的答案。

需要注意

  • n = 1的情况建议特判
  • 如果b[i] = 1时 j = i-1的情况,所以二分的起点l初始要小于i,直接设l = i-1即可

代码

#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define int long long
using namespace std;
​
const int maxn = 2e6 + 20;
const int mod = 1e9 + 7;
const int inf = 1LL << 60;#define db 0
#define test if (db) 
​
int n, m, k, t;
​
void solve() {
    cin >> n;
    vector<int> v(n);
    for (int i = 0; i < n; ++i) cin >> v[i];
    if (n == 1) {
        cout << "1\n";
        return;
    }
    --n;
    vector<int> a(n);
    for (int i = 0; i < n; ++i) a[i] = abs(v[i+1] - v[i]);
    vector<array<int, 20>> st(n+n);
    for (int i = 0; i < 20; ++i) for (int j = 0; j + (1LL << i) - 1 < n; ++j) {
        if (!i) st[j][i] = a[j]; else st[j][i] = __gcd(st[j][i-1], st[j+(1<<(i-1))][i-1]);
    }
​
    function ask = [&](int l, int r) -> int {
        if (l > r) return 1;
        int k = __lg(r-l+1);
        return __gcd(st[l][k], st[r-(1<<k)+1][k]);
    };
    int ans = 1;
    for (int i = 0; i < n; ++i) {
        int l = i-1, r = n-1;
        while (l < r) {
            int m = (l+r+1) >> 1;
            if (ask(i, m) > 1) l = m; else r = m-1; 
        }
        ans = max(ans, r-i+2); 
    }
    cout << ans << '\n';
}
​
​
void refresh() {
    
}
    
​
signed main() {
    IOS
    t = 1;
    cin >> t;
    while (t--) {
        solve();
        refresh();
    }
    return 0;
}