Simon has an array a1, a2, ..., an, consisting of n positive integers. Today Simon asked you to find a pair of integers l, r (1 ≤ l ≤ r ≤ n), such that the following conditions hold:
- there is integer j (l ≤ j ≤ r), such that all integers al, al + 1, ..., ar are divisible by aj;
- value r - l takes the maximum value among all pairs for which condition 1 is true;
Help Simon, find the required pair of numbers (l, r). If there are multiple required pairs find all of them.
The first line contains integer n (1 ≤ n ≤ 3·105).
The second line contains n space-separated integers a1, a2, ..., an (1 ≤ ai ≤ 106).
Print two integers in the first line — the number of required pairs and the maximum value of r - l. On the following line print all l values from optimal pairs in increasing order.
5
4 6 9 3 6
1 3
2
5
1 3 5 7 9
1 4
1
5
2 3 5 7 11
5 0
1 2 3 4 5
In the first sample the pair of numbers is right, as numbers 6, 9, 3 are divisible by 3.
In the second sample all numbers are divisible by number 1.
In the third sample all numbers are prime, so conditions 1 and 2 are true only for pairs of numbers (1, 1), (2, 2), (3, 3), (4, 4), (5, 5).
题目大意:给出长度为n的序列a[i],要求找到所有满足下列两个条件的子序列a[l],a[l+1],…,a[r]的个数:
1.存在l<=j<=r,使得a[j]是a[l],a[l+1],…,a[r]的最大公因数
2.在所有满足1的子序列中取r-l最长的.
分析:一个序列满足要求当且仅当min = gcd,关键的问题就是如何快速地求出min和gcd,最好是O(1),直接ST表就可以了.接下来二分枚举区间.一般这种求有多少个区间的都是先固定一个左端点然后二分右端点,但是这道题中min和gcd的单调性相同,不能直接这样二分,题目要求最大长度,那么直接二分长度,再枚举起点判断即可.
#include <cmath> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; const int maxn = 300010; int n, f[maxn][22], g[maxn][22], ans, anss[300010], tot, cnt, t[300010], anscnt; int gcd(int a, int b) { if (!b) return a; return gcd(b, a % b); } void init() { for (int j = 1; j <= 20; j++) for (int i = 1; i + (1 << j) - 1 <= n; i++) { f[i][j] = min(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]); g[i][j] = gcd(g[i][j - 1], g[i + (1 << (j - 1))][j - 1]); } } int geta(int l, int r) { int k = (int)((log(r - l + 1)) / log(2.0)); return min(f[l][k], f[r - (1 << k) + 1][k]); } int getb(int l, int r) { int k = (int)((log(r - l + 1)) / log(2.0)); return gcd(g[l][k], g[r - (1 << k) + 1][k]); } bool solve(int x) { cnt = 0; int tott = 0; memset(t, 0, sizeof(t)); for (int i = 1; i + x <= n; i++) if (geta(i, i + x) == getb(i, i + x)) { cnt++; t[++tott] = i; } if (cnt) { if (x > ans) { memcpy(anss, t, sizeof(t)); tot = tott; anscnt = cnt; } return true; } return false; } int main() { scanf("%d", &n); for (int i = 1; i <= n; i++) { scanf("%d", &f[i][0]); g[i][0] = f[i][0]; } init(); int l = 0, r = n; while (l <= r) { int mid = (l + r) >> 1; if (solve(mid)) { l = mid + 1; ans = mid; } else r = mid - 1; } if (ans != 0) { printf("%d %d ", anscnt, ans); for (int i = 1; i <= tot; i++) printf("%d ", anss[i]); } else { printf("%d %d ", n, ans); for (int i = 1; i <= n; i++) printf("%d ", i); } return 0; }