口算训练 - HDU 6287 - 唯一分解定理 + 二分查找

口算训练 - HDU 6287 - 唯一分解定理 + 二分查找

唯一分解定理

一个合数N可以展开成若干个质数幂相乘的形式。

\(N = p_1^{e_1}p_2^{e_2}...p_n^{e_n}\)

一个数\(M\)如果是\(N\)的倍数,则\(M\)的分解式中对应的幂的指数都应不小于\(N\)

本题思路

本题检验\(a_l*a_{l+1}*a_{l+2}...*a_{r-1}*a_r\)\(d\)的倍数关系,只需要检验\([l,r]\)区间分解质因数后各个质数的指数值与\(d\)对应的质数的指数值的大小关系。

我们可以预处理数组的质因数分解情况,记录每一个质数是由原数组中哪一个数分解得到的。

分解得到质因数的代码为

inline void decompose(int pos,int x,int arr[],vector<int> G[MaxN]){
  // (合数x在数组中的位置,合数x的大小,原数组,记录质数出现位置的变长数组)
    for (int i = 2; i * i <= x; i++) {
        while(x % i == 0){
            G[i].push_back(pos);
            x /= i;
        }
    }
    if(x > 1){
        G[x].push_back(pos);
    }
}

假设给定序列为 4,8,12,15,20

可以得到质数的出现情况

G[2] = <1,1,2,2,2,3,3,5,5>
G[3] = <3,4>
G[5] = <4,5>

我们可以得到,对于质数p,其在区间[l,r]出现的总个数为

int sum = upper_bound(G[p].begin(),G[p].end(),r) - lower_bound(G[p].begin(),G[p].end(),l);

代码

#include <cstdio>
#include <vector>
#include <algorithm>
#define MaxN 100000+5
using namespace std;

inline void decompose(int pos,int x,int arr[],vector<int> G[MaxN]){
    for (int i = 2; i * i <= x; i++) {
        while(x % i == 0){
            G[i].push_back(pos);
            x /= i;
        }
    }
    if(x > 1){
        G[x].push_back(pos);
    }
}


int main(){
    int t;
    scanf("%d",&t);
    while (t--) {
        int n,m;
        int arr[MaxN];
        int l,r,val;
        vector<int> G[MaxN];
        scanf("%d %d",&n,&m);
        for(int i = 1; i <= n; i++){
            scanf("%d",&arr[i]);
        }
        for(int i = 1; i <= n; i++){
            decompose(i,arr[i],arr,G);
        }
        while (m--) {
            bool flag = true;
            scanf("%d %d %d",&l,&r,&val);
            for(int i = 2; i * i <= val; i++){
                int cnt = 0;
                while (val % i == 0) {
                    cnt++;
                    val /= i;
                }
                if(cnt){
                    int sum = (int)(upper_bound(G[i].begin(),G[i].end(),r) - lower_bound(G[i].begin(),G[i].end(),l));
                    if(sum < cnt){
                        flag = false;
                        break;
                    }
                }
            }
            if(flag && val > 1){
                int sum = (int)(upper_bound(G[val].begin(),G[val].end(),r)-lower_bound(G[val].begin(),G[val].end(),l));
                if(sum == 0){
                    flag = false;
                }
            }
            
            if(flag)
                puts("Yes");
            else puts("No");
        }
    }
    return 0;
}

posted @ 2020-09-09 13:04  popozyl  阅读(154)  评论(0编辑  收藏  举报