能被多个质数整除的第K长子段 (849126) 题解

暴力做法:
首先我们转换一下题意,要求存在至少X个质数可以整除A[l]~A[r]之间的所有数,等价于GCD(A[l], A[l + 1], A[l + 2], ..., A[r])存在至少X个不同的质因数。因此我们可以暴力枚举所有可能的数对(l, r),然后求出GCD(A[l], A[l + 1], A[l + 2], ..., A[r]),并对其进行质因数分解,如果存在至少X个不同的质因数,说明这是一个合法的数对。那么我们最后只需记录下所有合法的数对并排序,找到第K长的数对即可。

int GetKthLength(vector<int>& A, int X, int K) {
    int N = 10000000;
    int n = A.size();
    vector <int> isOk(N + 5, false);
    for (int i = 2; i <= N; i++) {
        int cur = i;
        int s = 0, p = 2;
        while (p * p <= cur) {
            if (cur % p == 0) {
                s++;
                while (cur % p == 0) {
                    cur /= p;
                }
            }
            p++;
        }
        if (cur > 1) {
            s++;
        }
        isOk[i] = (s >= X);
    }
    vector <int> v;
    for (int l = 0; l < n; l++) {
        int gcd = A[l];
        if (isOk[gcd]) {
            v.push_back(-1);
            for (int r = l + 1; r < n; r++) {
                gcd = __gcd(gcd, A[r]);
                if (isOk[gcd]) {
                    v.push_back(-(r - l + 1));
                } else {
                    break;
                }
            }
        }
    }
    if (v.size() < K) {
        return -1;
    }
    sort(v.begin(), v.end());
    return -v[K - 1];
}

正解:
使用欧拉筛法,可以用O(N)时间计算出1到N之间每个数的最小质因数,并可以在筛法过程中统计1到N之间每个数有多少个不同的质因数。
然后我们考虑在枚举数对的过程中,如果r固定,因为GCD满足结合律,有

也就是说GCD随着在l递减的过程中不会增加。进一步的,如果
图片说明
那么有
图片说明
根据GCD的定义,显然上述左式是上述右式的一个真因数,那么左式大小不超过右式的一半,易证数对中的r固定之后
图片说明
最多有图片说明 种不同的取值,且每种取值时都对应连续的一段l,因此我们可以对于每个r维护所有这些区间
最后考虑计算第K大长度,我们可以通过二分答案Ans,将原问题转换为计算有多少长度大于等于Ans的数对,只需要对于所有可能的r,枚举所有可能的,根据上一步预处理的结果得到可能的l的范围,并累加有多少个长度大于等于Ans的数对即可。
至此问题完美解决,复杂度为
欧拉筛法预处理复杂度 + 对于每个r预处理不同GCD的复杂度 + 二分答案计算复杂度,既
O(1000w) + O(n * log(1000W)) + O(log(n) * n * log(1000w)
是可以接受的复杂度

int CountMoreThanX(int x, vector <bool> &isOk, vector <vector <pair <int, int> > > &gcd) {
    int s = 0, n = (int)gcd.size();
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < gcd[i].size() - 1; j++) {
            if (!isOk[gcd[i][j].second]) {
                break;
            }
            int len0 = i - gcd[i][j].first + 1, len1 = i - gcd[i][j + 1].first;
            if (len0 >= x) {
                s += (len1 - len0 + 1);
            } else if (len1 >= x) {
                s += (len1 - x + 1);
            }
        }
    }
    return s;
}

/**
 * 求满足条件的第K大长度
 * @param A int整型vector 牛牛的数组A
 * @param X int整型 至少要存在X个不同的质数
 * @param K int整型 牛牛希望找到第K大的长度
 * @return int整型
 */
int GetKthLength(vector<int>& A, int X, int K) {
    int N = 10000000;
    int n = A.size();
    vector <int> cnt(N + 5, 0);
    vector <int> nums(N + 5, 0);
    vector <int> notPrime(N + 5, 0);
    vector <int> primes;
    nums[1] = 0;
    nums[2] = 1;
    notPrime[1] = 1;
    for (int i = 2; i <= N; i++) {
        if (!notPrime[i]) {
            primes.push_back(i);
            nums[i] = 1;
        }
        for (int j = 0; j < (int)primes.size() && i * primes[j] <= N; j++) {
            int p = primes[j];
            notPrime[i * p] = true;
            if (i % p == 0) {
                nums[i * p] = nums[i];
                break;
            } else {
                nums[i * p] = nums[i] + 1;
            }
        }
    }
    vector <bool> isOk(N + 5, false);
    for (int i = 2; i <= N; i++) {
        isOk[i] = (nums[i] >= X);
    }

    vector <vector <pair <int, int> > > gcd(n);
    for (int i = 0; i < n; i++) {
        gcd[i].push_back(make_pair(i, A[i]));
        if (i > 0) {
            for (auto pre : gcd[i - 1]) {
                int curGcd = __gcd(A[i], pre.second);
                if (curGcd != gcd[i].back().second) {
                    gcd[i].push_back(make_pair(pre.first, curGcd));
                }
            }
        }
    }
    for (int i = 0; i < n; i++) {
        gcd[i].push_back(make_pair(-1, 0));
    }
    if (CountMoreThanX(1, isOk, gcd) < K) {
        return -1;
    }
    int l = 1, r = n;
    while (l < r) {
        int mid = l + ((r - l + 1) >> 1);
        if (CountMoreThanX(mid, isOk, gcd) < K) {
            r = mid - 1;
        } else {
            l = mid;
        }
    }

    return l;
}
全部评论

相关推荐

点赞 收藏 评论
分享
牛客网
牛客企业服务