口算訓練 - HDU 6287 - 唯一分解定理 + 二分
阿新 • • 發佈:2020-09-09
口算訓練 - 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; }