bzoj4026

首先要知道phi(x^k)=x^k-x^(k-1)=x^(k-1)*(x-1)=x^k*((x-1)/x)

然后用主席树维护区间不同种质数的贡献(每种质数贡献(x-1)/x))就好了

(和HH的项链比较像)

但是卡了一天,一直T......qwq

后面发现是找质因子的时候复杂度过大,因为如果有一个大质数,就会几乎跑满,如果都是大质数就......

然后特判了如果除到质数就break就能A了

/**************************************************************

    Problem: 4026

    User: syh0313

    Language: C++

    Result: Accepted

    Time:5720 ms

    Memory:100504 kb

****************************************************************/

 

#include <iostream>

#include <cstdio>

#include <cstdlib>

#include <cstring>

#include <string>

#include <cmath>

#include <algorithm>

#include <map>

#include <vector>

#define lch a[n].lc

#define rch a[n].rc

using namespace std;

const int maxn=50010;

const int mo=1000777;

int n,m,v[maxn],cnt,prime[1000010],st[1000010],root[maxn],topt,lim;

long long p[1000010],ans,sum[maxn],ss,in[maxn];

bool f[1000010];

struct da{int lc,rc;long long sum;}a[maxn*100];

vector<int>nt[maxn],pri[maxn];

inline long long po(long long a,int b)

{

    if (b==0) return 1;

    if (b==1) return a;

    long long c=po(a,b/2);

    if (b&1) return c*c%mo*a%mo;else return c*c%mo;

}

inline long long inv(long long x){return po(x,mo-2);}

inline void init()

{

    memset(f,1,sizeof f); f[1]=0; st[1]=n+1; sum[0]=1ll; in[0]=1;

    register int i;

    for (i=2;i<=1000000;i++)

    {

        st[i]=n+1;

        if (f[i])

        {

            prime[++cnt]=i;

            p[i]=1ll*(i-1)*inv(1ll*i)%mo;

        }

        for (int j=1;j<=cnt && i*prime[j]<=1000000;j++)

        {

            f[i*prime[j]]=0;

            if (i%prime[j]==0) break;

        }

    }

}

inline void updata(int n){a[n].sum=a[lch].sum*a[rch].sum%mo;}

inline void build_tree(int &n,int l,int r)

{

    n=++topt; a[n].sum=1ll;

    if (l==r) {a[n].sum=1ll; return;}

    int mid=(l+r)>>1;

    build_tree(lch,l,mid); build_tree(rch,mid+1,r);

}

inline void tree_mul(int old,int &n,int l,int r,int lc,long long k)

{

    if (n<=lim) n=++topt;

    if (l==r)

    {

        if (!a[n].sum) a[n].sum=a[old].sum*k%mo;

         else a[n].sum=a[n].sum*k%mo;

        return;

    }

    int mid=(l+r)>>1;

    if (lc<=mid)

    {

        if (!rch) rch=a[old].rc;

        tree_mul(a[old].lc,lch,l,mid,lc,k);

    }

    else

    {

        if (!lch) lch=a[old].lc;

        tree_mul(a[old].rc,rch,mid+1,r,lc,k);

    }

    updata(n);

}

inline long long qury(int old,int n,int L,int R,int l,int r)

{

    if (L==l && R==r) {ss=ss*a[old].sum%mo; return a[n].sum;}

    int mid=(L+R)>>1;

    if (r<=mid) return qury(a[old].lc,lch,L,mid,l,r);

    else if (l>=mid+1) return qury(a[old].rc,rch,mid+1,R,l,r);

return qury(a[old].lc,lch,L,mid,l,mid)*qury(a[old].rc,rch,mid+1,R,mid+1,r)%mo;

}

inline int read()

{

    int xx=0,ff=1; char c=getchar();

    while (c<'0' || c>'9') {if (c=='-') ff=-1; c=getchar();}

    while (c>='0' && c<='9') {xx=(xx<<1)+(xx<<3)+c-'0'; c=getchar();}

return xx*ff;

}

int main()

{

    //freopen("1.in","r",stdin);

    //freopen("1.out","w",stdout);

    n=read(); m=read(); init(); register int i,j;

    for (i=1;i<=n;i++) v[i]=read(),sum[i]=sum[i-1]*v[i]%mo,in[i]=inv(sum[i]);

    for (i=n;i>=1;i--)

    {

        int x=v[i];

        for (j=1;prime[j]<=x;j++)

        {

            if (f[x])

            {

                nt[i].push_back(st[x]);

                pri[i].push_back(x);

                st[x]=i;

                break;

            }

            int num=0;

            while (x%prime[j]==0) {num++; x/=prime[j];}

            if (num)

            {

                nt[i].push_back(st[prime[j]]);

                pri[i].push_back(prime[j]);

                st[prime[j]]=i;

            }

        }

    }

    build_tree(root[0],1,n+1);

    for (i=1;i<=n;i++)

    {

        lim=topt;

        if (v[i]==1)

        {

            root[i]=++topt; a[topt].lc=a[root[i-1]].lc; a[topt].rc=a[root[i-1]].rc;

            continue;

        }

        for (int j=0;j<nt[i].size();j++)

         tree_mul(root[i-1],root[i],1,n+1,nt[i][j],p[pri[i][j]]);

    }

    while (m--)

    {

        int l,r; l=read(); r=read(); ss=1ll; l^=ans; r^=ans;

        ans=sum[r]*qury(root[l-1],root[r],1,n+1,r+1,n+1)%mo*in[l-1]%mo*inv(ss)%mo;

        printf("%lld\n",ans);

    }

return 0;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值