当前位置: 代码迷 >> 综合 >> B. Integers Have Friends(cf)二分 + st表
  详细解决方案

B. Integers Have Friends(cf)二分 + st表

热度:66   发布时间:2023-11-23 05:49:04.0

 原题链接:Problem - 1548B - Codeforces

解决RMQ(区间最值)问题的算法。

总结的来说求rmq问题有多种方法:线段树,ST表等 线段树预处理O(nlogn),查询O(logn),支持在线修改 ST表预处理O(nlogn),查询O(1),但不支持在线修改

先用st表预处理,然后再使用二分求出最大的区间长度,每次查询一个区间的时候用st表十分方便。

我的二分在这里wa了很多发,注意如果n == 2的时候这个二分是进不了while循环的,所以我单独拿出来处理了;然后这个二分还要想清楚就是,如果在这个区间里没有答案,它就会以最左端点为答案,所以最后还要把得出的l特判一下---->或者,我刚才去试了一下,直接把左端点改为0就万事大吉了(之前是怕左端点为0会出啥问题之类的)。

AC代码:

#include<bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
typedef pair<int, int> PII;
const double pi = acos(-1.0);
#define rep(i, n) for (int i = 1; i <= (n); ++i)
#define rrep(i, n) for (int i = n; i >= (1); --i)
typedef long long ll;
#define sqar(x) ((x)*(x))const int N = 2e5 + 10;
ll a[N];
int Log[N];
ll dp[N][21]; //以下标i为起点,区间长度2^j的区间维护的值ll gcd(ll a, ll b)
{return b == 0 ? a : gcd(b, a % b);
}int n;
void init(){
for (int i = 2; i < N; i++)Log[i] = Log[i >> 1] + 1;
}void st() {for (int i = 1; i < n; i++)dp[i][0] = a[i];for (int j = 1; j <= 20; j++){for (int i = 1; i + (1 << j) - 1 <= n - 1; i++) {dp[i][j] = gcd(dp[i][j - 1], dp[i + (1 << (j - 1))][j - 1]);}}
}ll query(int l, int r) {int k = Log[r - l + 1];return gcd(dp[l][k], dp[r - (1 << k) + 1][k]);
}bool check(int x)
{for(int i = x; i < n; i++){if(query(i - x + 1, i) > 1ll) return 1;}return 0;
}int main() {int t;scanf("%d", &t);init();while(t--){scanf("%d", &n);for (int i = 1; i <= n; i++) scanf("%lld", &a[i]);if(n == 2){ //n等于2特判一下,因为后面写二分的时候如果n变成1了没进whileif(abs(a[2] - a[1]) == 1) puts("1");else puts("2");continue;}rep(i, n - 1){a[i] = abs(a[i + 1] - a[i]);}st();int l = 1, r = n - 1;int ans = 0;while(l < r){int mid = (l + r + 1) >> 1;if(check(mid)) l = mid;else r = mid - 1;}ans = l;if(!check(l)) ans = 0;printf("%d\n", ans + 1);}return 0;
}

  相关解决方案