我是靠谱客的博主 欢呼超短裙,最近开发中收集的这篇文章主要介绍Pair of Numbers CodeForces - 359D(st表,二分),觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

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.

Input
The first line contains integer n (1 ≤ n ≤ 3·105).

The second line contains n space-separated integers a1, a2, …, an (1 ≤ ai ≤ 106).

Output
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.

Examples
Input
5
4 6 9 3 6
Output
1 3
2
Input
5
1 3 5 7 9
Output
1 4
1
Input
5
2 3 5 7 11
Output
5 0
1 2 3 4 5
Note
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).

题意: 找出一段l~r,使得存在l ≤ i ≤ r,使得a[i]为这段数的最大公约数。输出最长的。
思路: 又一次体会到了st表的神奇(上一次是cf234a https://blog.csdn.net/tomjobs/article/details/102728843)

本题中,如果存在这样的i使得a[i]为这段的最大公约数,很明显a[i]得是这段的最小值。那么,我们只需要打出每一段的gcd和min,每次比较就可以看这段是否符合要求了。问题就变成了怎样确定段的长度。很明显,长度是具有单调性的(如果长的满足,那么短的也满足),所以直接二分长度就好了。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <vector>

using namespace std;

typedef long long ll;

const int maxn = 3e5 + 7;
vector<int>res,tmp;
int mi[maxn][22],gc[maxn][22],a[maxn],ans_len;
int n,m;

int gcd(int x,int y) {
    return y == 0 ? x : gcd(y,x % y);
}

void init() {
    for(int j = 1;j <= 20;j++) {
        for(int i = 1;i + (1 << j) - 1 <= n;i++) {
            mi[i][j] = min(mi[i][j - 1],mi[i + (1 << (j - 1))][j - 1]);
            gc[i][j] = gcd(gc[i][j - 1],gc[i + (1 << (j - 1))][j - 1]);
        }
    }
}

int query_mi(int l,int r) {
    int k = (int)log2(r - l + 1);
    return min(mi[l][k],mi[r - (1 << k) + 1][k]);
}

int query_gc(int l,int r) {
    int k = (int)log2(r - l + 1);
    return gcd(gc[l][k],gc[r - (1 << k) + 1][k]);
}

bool check(int len) {
    tmp.clear();
    for(int i = 1;i + len <= n;i++) {
        if(query_mi(i,i + len) == query_gc(i,i + len)) {
            tmp.push_back(i);
        }
    }
    if(tmp.size()) {
        return true;
    }
    return false;
}

int main() {
    scanf("%d",&n);
    for(int i = 1;i <= n;i++) {
        scanf("%d",&a[i]);
        gc[i][0] = mi[i][0] = a[i];
    }
    init();
    int l = 0,r = n - 1;
    int ans = 0;
    
    while(l <= r) {
        int mid = (l + r) >> 1;
        if(check(mid)) {
            ans = mid;
            res = tmp;
            l = mid + 1;
        }
        else {
            r = mid - 1;
        }
    }
    
    
    printf("%d %dn",res.size(),ans);
    for(int i = 0;i < res.size();i++) {
        printf("%d ",res[i]);
    }
    return 0;
}

貌似有更简便的方法,记录每个数左右扩展的大小。可以证明复杂度均为O(n)级别。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <vector>

using namespace std;

typedef long long ll;

const int maxn = 3e5 + 7;
int L[maxn],R[maxn],a[maxn];
vector<int>ans;

int main() {
    int n;scanf("%d",&n);
    for(int i = 1;i <= n;i++) {
        scanf("%d",&a[i]);
        L[i] = R[i] = i;
    }
    
    for(int i = 1;i <= n;i++) {
        int now = i - 1;
        while(now >= 1 && a[now] % a[i] == 0) {
            L[i] = L[now];
            now = L[now] - 1;
        }
    }
    for(int i = n;i >= 1;i--) {
        int now = i + 1;
        while(now <= n && a[now] % a[i] == 0) {
            R[i] = R[now];
            now = R[now] + 1;
        }
    }
    
    int mx = 0;
    for(int i = 1;i <= n;i++) {
        mx = max(mx,R[i] - L[i]);
    }
    
    for(int i = 1;i <= n;i++) {
        if(R[i] - L[i] == mx) {
            if(ans.empty()) {
                ans.push_back(L[i]);
            }
            else {
                if(L[i] != ans.back()) {
                    ans.push_back(L[i]);
                }
            }
        }
    }
    
    printf("%d %dn",ans.size(),mx);
    for(int i = 0;i < ans.size();i++) {
        printf("%d ",ans[i]);
    }
    return 0;
}

这个则是跳到右端点后面,因为右端点和i之间的数再怎么扩展也不会比原来的长。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <vector>

using namespace std;

typedef long long ll;

const int maxn = 3e5 + 7;
int L[maxn],R[maxn],a[maxn];
vector<int>ans;

int main() {
    int n;scanf("%d",&n);
    for(int i = 1;i <= n;i++) {
        scanf("%d",&a[i]);
    }
    
    int mx = 0;
    for(int i = 1;i <= n;) {
        int l = i,r = i;
        while(l >= 1 && a[l] % a[i] == 0)l--;l++;
        while(r <= n && a[r] % a[i] == 0)r++;r--;
        if(r - l > mx) {
            ans.clear();ans.push_back(l);
            mx = r - l;
        }
        else if(r - l == mx) {
            ans.push_back(l);
        }
        i = r + 1;
    }
    printf("%d %dn",ans.size(),mx);
    for(int i = 0;i < ans.size();i++) {
        printf("%d ",ans[i]);
    }
    return 0;
}

最后

以上就是欢呼超短裙为你收集整理的Pair of Numbers CodeForces - 359D(st表,二分)的全部内容,希望文章能够帮你解决Pair of Numbers CodeForces - 359D(st表,二分)所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(43)

评论列表共有 0 条评论

立即
投稿
返回
顶部