[Ynoi2015]此时此刻的光辉(莫队)

一道神题。。。自己写出来以后被卡常了。。。荣获洛谷最差解。。。

思路还是比较好想,对于每个数 \(\sqrt{n}\) 分块,对于 \(\sqrt{n}\) 以内的数,我们可以直接求出来。对于 \(\sqrt{n}\) 以上的数,我们用莫队求。

不过空间 \(O(\frac {n\sqrt{10^9}}{\log n})\) 开不下,非常优秀。。。

那我们就把前 $100$ 个质数求出来,其他就用莫队好了,转移均摊是 \(O(1)\) 的吧。。。

常数巨大,本人没卡常。记得要等一个没人的时候提交。

\(Code\ Below:\)

// luogu-judger-enable-o2
#include <bits/stdc++.h>
#define pii pair<int,int>
#define mp make_pair
#define F first
#define S second
using namespace std;
const int maxn=100000+10;
const int mod=19260817;
int n,m,lim,blo,a[maxn],cnt[maxn],sum[maxn][151],ans[maxn],now;
int inv[maxn],pri[maxn],vis[maxn],tot,num;
vector<pii> v[maxn];map<int,int> pos;

struct Query{
    int l,r,id;
}q[maxn];

inline bool cmp(const Query &a,const Query &b){
    if((a.l-1)/blo!=(b.l-1)/blo) return (a.l-1)/blo<(b.l-1)/blo;
    return a.r<b.r;
}

inline int read(){
    register int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    return (f==1)?x:-x;
}

inline void getpri(int n){
    for(int i=2;i<=n;i++){
        if(!vis[i]) pri[++tot]=i;
        for(int j=1;j<=tot&&i*pri[j]<=n;j++){
            vis[i*pri[j]]=1;
            if(i%pri[j]==0) break;
        }
    }
}

inline void pre(int val,int x){
    int cnt;
    for(int i=1;i<=tot;i++)
        if(val%pri[i]==0){
            cnt=0;
            while(val%pri[i]==0) cnt++,val/=pri[i];
            if(i<=150) sum[x][i]=cnt;
            else {
                if(pos.find(pri[i])==pos.end()) pos[pri[i]]=++num;
                v[x].push_back(mp(pos[pri[i]],cnt));
            }
        }
    if(val>1){
        if(pos.find(val)==pos.end()) pos[val]=++num;
        v[x].push_back(mp(pos[val],1));
    }
}

inline void add(int x){
    for(int i=0,j=v[x].size();i<j;i++){
        now=1ll*now*inv[cnt[v[x][i].F]]%mod;
        cnt[v[x][i].F]+=v[x][i].S;
        now=1ll*now*cnt[v[x][i].F]%mod;
    }
}

inline void del(int x){
    for(int i=0,j=v[x].size();i<j;i++){
        now=1ll*now*inv[cnt[v[x][i].F]]%mod;
        cnt[v[x][i].F]-=v[x][i].S;
        now=1ll*now*cnt[v[x][i].F]%mod;
    }
}

int main()
{
    n=read(),m=read();blo=sqrt(n);
    for(int i=1;i<=n;i++) a[i]=read(),lim=max(lim,a[i]);
    getpri((int)sqrt(lim));
    inv[0]=inv[1]=1;
    for(int i=2;i<=n;i++) inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod;
    for(int i=1;i<=n;i++) pre(a[i],i);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=150;j++) sum[i][j]+=sum[i-1][j];
    for(int i=1;i<=n;i++) cnt[i]=1;
    for(int i=1;i<=m;i++) q[i].l=read(),q[i].r=read(),q[i].id=i;
    sort(q+1,q+m+1,cmp);
    int L=1,R=0;now=1;
    for(int i=1;i<=m;i++){
        while(R<q[i].r) add(++R);
        while(R>q[i].r) del(R--);
        while(L<q[i].l) del(L++);
        while(L>q[i].l) add(--L);
        ans[q[i].id]=now;
        for(int j=1;j<=150;j++) ans[q[i].id]=1ll*ans[q[i].id]*(sum[q[i].r][j]-sum[q[i].l-1][j]+1)%mod;
    }
    for(int i=1;i<=m;i++) printf("%d\n",ans[i]);
    return 0;
}
posted @ 2019-02-03 18:02  Owen_codeisking  阅读(250)  评论(0编辑  收藏  举报