口算训练 - 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;
}
---- suffer now and live the rest of your life as a champion ----