題目鏈接
題目思路
前言
比賽的時候,其實自己已經想到了和答案一樣的思路,但是卻沒寫,實屬不該。觀察a[i]<=300其實我就知道肯定是要質因數分解。碼力還要加強
正文
分析一下,答案就是所有數質因數分解,每一個質數的最大次數。然後乘起來即可。注意z是1e9,他分解質因數,不只是前300中的質數,所以最後還要乘以z
用st表要注意被卡空間了,所以要用short int
如果利用 線段樹,會發現當我們quriy的時候,62棵線段樹遍歷順序的一致的,所以我們應該 62 棵線段樹同時 進行而不是 進行 62 次quriy
親身實驗62次quiry會t,但是該怎麼只要1次遍歷呢,其實quiry的時候沒必要返回,直接標記那些tree中的node要用即可,放在set中就行了
代碼
#include<set>
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn=1e5+5;
set<int> pos;
int n,t,mod,a[maxn],tree[maxn<<2][63],base[maxn][63];
int prime[310],isprime[70],cnt;
void init(){
for(int i=2;i<=300;i++){//300以內62個素數
if(!prime[i]){
for(int j=i*i;j<=300;j=j+i){
prime[j]=1;
}
isprime[++cnt]=i;
}
}
}
void build(int node,int l,int r,int opt){
if(l==r){
tree[node][opt]=base[l][opt];
return ;
}
int mid=(l+r)/2;
build(node<<1,l,mid,opt);
build(node<<1|1,mid+1,r,opt);
tree[node][opt]=max(tree[node<<1][opt],tree[node<<1|1][opt]);
}
void query(int node,int L,int R,int l,int r,int opt){
if(L<=l&&r<=R){
pos.insert(node);
return ;
}
int mid=(l+r)/2;
if(mid>=L) query(node<<1,L,R,l,mid,opt);
if(mid<R) query(node<<1|1,L,R,mid+1,r,opt);
}
ll qpow(int a,int b){
ll ans=1,base=a;
while(b>0){
if(b&1){
ans=ans*base%mod;
}
b=b>>1;
base=base*base%mod;
}
return ans;
}
int main(){
init();
scanf("%d %d %d",&n,&mod,&t);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
for(int j=1;j<=62;j++){//質因分解
cnt=0;
while(a[i]%isprime[j]==0){
a[i]=a[i]/isprime[j];
cnt++;
}
base[i][j]=cnt;
}
}
for(int i=1;i<=62;i++){
build(1,1,n,i);
}
while(t--){
int x,y,z;
ll ans=1;
pos.clear();
scanf("%d %d %d",&x,&y,&z);
query(1,x,y,1,n,1);//只要隨意查詢一次即可
for(int i=1;i<=62;i++){
int base1=0,base2=0;
for(set<int>::iterator ite=pos.begin();ite!=pos.end();ite++){
base1=max(base1,tree[*(ite)][i]);
}
while(z%isprime[i]==0){
z=z/isprime[i];
base2++;
}
ans=ans*qpow(isprime[i],max(base1,base2))%mod;
}
ans=ans*z%mod;//注意z可能不止分解成300以內的素數
printf("%lld\n",ans);
}
return 0;
}