【JZOJ 4638】 第三条跑道

35 篇文章 0 订阅
5 篇文章 0 订阅

Description

这里写图片描述
这里写图片描述
(%%%WerkeyTom_FTD)

Analysis

首先,我们知道, φ(x)=kφ(pakk)
因为ai,x很小,所以可以把他们分解质因数。
600以内的质数只有109个,所以可以开109颗线段树,维护该质数在区间中的指数,乱搞一下。

Code

#include<cstdio>
#include<cstring>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
typedef long long ll;
const ll N=10010,M=110,mo=1e8+7;
ll ind,num,ans,
prime[]={1,2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,223,227,229,233,239,241,251,257,263,269,271,277,281,283,293,307,311,313,317,331,337,347,349,353,359,367,373,379,383,389,397,401,409,419,421,431,433,439,443,449,457,461,463,467,479,487,491,499,503,509,521,523,541,547,557,563,569,571,577,587,593,599};
ll n,m,a[M],b[M],c[M][N];
struct segment
{
    ll n,x,lz;
}tr[M][N*4];
char ch;
void read(ll &n)
{
    int t=0,p=1;
    for(ch=getchar();ch<'0' || ch>'9';ch=getchar())
        if(ch=='-') p=-1;
    for(;'0'<=ch && ch<='9';ch=getchar()) t=t*10+ch-'0';
    n=t*p;
}
void pri(ll n,int num)
{
    fo(i,1,109)
    {
        while(n%prime[i]==0) n/=prime[i],c[i][num]++;
        if(n==1) break;
    }
}
void deco(ll n)
{
    m=0;
    fo(i,1,109)
        if(n%prime[i]==0)
        {
            a[++m]=i,b[m]=0;
            while(n%prime[i]==0) n/=prime[i],b[m]++;
        }
}
ll qmi(ll x,ll n)
{
    ll t=1;
    for(;n;n>>=1)
    {
        if(n&1) t=t*x%mo;
        x=x*x%mo;
    }
    return t;
}
void up(int k,int v)
{
    tr[k][v].x=tr[k][v+v].x+tr[k][v+v+1].x;
    tr[k][v].n=tr[k][v+v].n+tr[k][v+v+1].n;
}
void build(int k,int v,int l,int r)
{
    if(l==r)
    {
        tr[k][v].x=c[k][l];
        tr[k][v].n=(tr[k][v].x>0);
        return;
    }
    int mid=(l+r)>>1;
    build(k,v+v,l,mid);
    build(k,v+v+1,mid+1,r);
    up(k,v);
}
void update(segment &a,ll len,ll z)
{
    a.x+=len*z;
    a.lz+=z;
    a.n=len;
}
void down(int k,int v,int l,int r)
{
    if(!tr[k][v].lz) return;
    int mid=(l+r)>>1;
    update(tr[k][v+v],mid-l+1,tr[k][v].lz);
    update(tr[k][v+v+1],r-mid,tr[k][v].lz);
    tr[k][v].lz=0;
}
void change(int k,int v,int l,int r,int x,int y,ll z)
{
    if(l==x && r==y)
    {
        update(tr[k][v],r-l+1,z);
        return;
    }
    down(k,v,l,r);
    int mid=(l+r)>>1;
    if(y<=mid) change(k,v+v,l,mid,x,y,z);
    else
    if(x>mid) change(k,v+v+1,mid+1,r,x,y,z);
    else change(k,v+v,l,mid,x,mid,z),change(k,v+v+1,mid+1,r,mid+1,y,z);
    up(k,v);
}
void query(int k,int v,int l,int r,int x,int y)
{
    if(l==x && r==y)
    {
        ind+=tr[k][v].x;
        num+=tr[k][v].n;
        return;
    }
    down(k,v,l,r);
    int mid=(l+r)>>1;
    if(y<=mid) query(k,v+v,l,mid,x,y);
    else
    if(x>mid) query(k,v+v+1,mid+1,r,x,y);
    else
    query(k,v+v,l,mid,x,mid),query(k,v+v+1,mid+1,r,mid+1,y);
}
int main()
{
    ll _,tp,l,r,x;
    read(n);
    fo(i,1,n)
    {
        read(x);
        pri(x,i);
    }
    fo(i,1,109) build(i,1,1,n);
    read(_);
    while(_--)
    {
        read(tp),read(l),read(r);
        if(!tp)
        {
            read(x);
            deco(x);
            fo(i,1,m) change(a[i],1,1,n,l,r,b[i]);
        }
        else
        {
            ans=1;
            fo(i,1,109)
            {
                ind=num=0;
                query(i,1,1,n,l,r);
                ans=ans*qmi(prime[i],ind-num)%mo*qmi(prime[i]-1,num)%mo;
            }
            printf("%lld\n",ans);
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值