HDU6287 口算訓練
阿新 • • 發佈:2018-12-19
Problem Description
小Q非常喜歡數學,但是他的口算能力非常弱。因此他找到了小T,給了小T一個長度為n的正整數序列a1,a2,...,an,要求小T丟擲m個問題以訓練他的口算能力。 每個問題給出三個正整數l,r,d,小Q需要通過口算快速判斷al×al+1×...×ar−1×ar是不是d的倍數。 小Q迅速地回答了出來,但是小T並不知道正確答案是什麼,請寫一個程式幫助小T計算這些問題的正確答案。
Input
第一行包含一個正整數T(1≤T≤10),表示測試資料的組數。 每組資料第一行包含兩個正整數n,m(1≤n,m≤100000),分別表示序列長度以及問題個數。 第二行包含n個正整數a1,a2,...,an(1≤ai≤100000),表示序列中的每個數。 接下來m行,每行三個正整數l,r,d(1≤l≤r≤n,1≤d≤100000),表示每個問題。
Output
對於每個問題輸出一行,若是倍數,輸出Yes,否則輸出No。
Sample Input
1
5 4
6 4 7 2 5
1 2 24
1 3 18
2 5 17
3 5 35
Sample Output
Yes
No
No
Yes
Source
思路:將所給數列中的每一個數都進行質數分解,用二位vector陣列存質數因子在哪一個數中出現過。然後對於每一個要查詢的區間和數字d,先將數字d分解,每分解一次查詢一下查詢區間中是否有足夠多的因子個數;查詢的方法是二分,先查詢下標大於等於L並且含有該質數因子的第一個數字下標,再查詢該區間內是否有足夠多的該質數因子。
#include<bits/stdc++.h> using namespace std; const int N=100010; int x,n,k,L,R,d; vector<int>v[N]; void add(int val,int num) { for(int i=2;i*i<=val;i++) { while(val%i==0) { v[i].push_back(num); val/=i; } } if(val>1) v[val].push_back(num); } int ask(int val,int num) { int l=0,r=v[val].size()-1,mid,t=-1; while(l<=r) { mid=(l+r)/2; if(v[val][mid]>=L) { t=mid; r=mid-1; } else l=mid+1; } r=v[val].size()-1; if(t<0) return 0; while(num--) { if(t>r) return 0; if(v[val][t]>R) return 0; t++; } return 1; } int solve(int val) { for(int i=2;i*i<=val;i++) { int t=0; if(val%i==0) { while(val%i==0) { t++; val/=i; } if(!ask(i,t)) return 0; } } if(val>1) { if(!ask(val,1)) return 0; } return 1; } int main() { int T; scanf("%d",&T); while(T--) { for(int i=0;i<=N;i++) v[i].clear(); scanf("%d%d",&n,&k); for(int i=1;i<=n;i++) { scanf("%d",&x); add(x,i); } for(int i=1;i<=k;i++) { scanf("%d%d%d",&L,&R,&d); if(solve(d)) printf("Yes\n"); else printf("No\n"); } } return 0; }