集訓隊選拔賽 噁心心的題(線段樹)

題目鏈接

題目思路

前言

比賽的時候,其實自己已經想到了和答案一樣的思路,但是卻沒寫,實屬不該。觀察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;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章