1. 程式人生 > 實用技巧 >口算訓練 - HDU 6287 - 唯一分解定理 + 二分

口算訓練 - 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;
}