码迷,mamicode.com
首页 > 其他好文 > 详细

【51nod1642】区间欧拉函数

时间:2018-05-16 23:10:59      阅读:220      评论:0      收藏:0      [点我收藏+]

标签:详细   des   amp   sort   维护   www.   rip   str   scanf   

Description

求区间$[l,r]$权值积的欧拉函数值。
详细题面

Solution

直接考虑一个数的欧拉函数如何计算,有:$φ(x)=x\prod \dfrac{p-1}{p}$($p$是$x$的质因子)
要求一段区间权值积欧拉函数值其实就是要求这个区间包含不同质数的$\dfrac{p-1}{p}$的积乘以区间的积。

考虑离线,把询问按照$r$排序,区间不同质数乘积可以用树状数组维护。

Code

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define fo(i,j,k) for(int i=j;i<=k;++i)
#define fd(i,j,k) for(int i=j;i>=k;--i)
using namespace std;
typedef long long ll;
const int N=2e5+10,mo=1e9+7;
struct node{
    int l,r,p;
}b[N];
int a[N],n;
ll s[N],tr[N];
int pos[N*5],an[N];
int pr[N],mp[N*5];
bool bz[N*5];
int mx=0;
void mul(int x,int t){
    for(;x<=n;x+=x&-x) tr[x]=tr[x]*t%mo;
}
ll calc(ll x){
    ll tmp=1;
    for(;x;x-=x&-x) tmp=tmp*tr[x]%mo;
    return tmp;
}
ll pow(ll x,int y){
    ll t=1;
    while(y){
        if(y&1) t=t*x%mo;
        y>>=1,x=x*x%mo;
    }
    return t;
}
bool cmp(node x,node y){
    return x.r<y.r;
}
void pre(){
    fo(i,2,mx){
        if(!bz[i]) pr[++pr[0]]=i,bz[i]=1,mp[i]=i;
        fo(j,1,pr[0]){
            int t=i*pr[j];
            if(t>mx) break;
            bz[t]=1,mp[t]=min(mp[i],pr[j]);
            if(i%pr[j]==0) break;
        }
    }
}
void add(int p){
    int x=a[p];
    /*for(int i=2;i*i<=x;i++)
    if(x%i==0){
        while(x%i==0) x/=i;
        ll t=(ll)(i-1)*pow(i,mo-2)%mo;
        if(pos[i]) mul(pos[i],pow(t,mo-2));
        pos[i]=p,mul(p,t);
    }
    if(x>1){
        ll t=(ll)(x-1)*pow(x,mo-2)%mo;
        if(pos[x]) mul(pos[x],pow(t,mo-2));
        pos[x]=p,mul(p,t);
    }*/
    while(x>1){
        int i=mp[x];
        while(x%i==0) x/=i;
        ll t=(ll)(i-1)*pow(i,mo-2)%mo;
        if(pos[i]) mul(pos[i],pow(t,mo-2));
        pos[i]=p,mul(p,t);
    }
}
int main()
{
    scanf("%d",&n);
    s[0]=1;
    fo(i,1,n){
        scanf("%d",&a[i]),s[i]=s[i-1]*a[i]%mo;
        mx=max(mx,a[i]),tr[i]=1;
    }
    pre();
    int q;
    scanf("%d",&q);
    fo(i,1,q) scanf("%d %d",&b[i].l,&b[i].r),b[i].p=i;
    sort(b+1,b+q+1,cmp);
    int p=0;
    fo(i,1,n){
        add(i);
        while(p<q && b[p+1].r==i){
            p++;
            int wz=b[p].p;
            an[wz]=calc(b[p].r)*pow(calc(b[p].l-1),mo-2)%mo;
            an[wz]=an[wz]*s[b[p].r]%mo*pow(s[b[p].l-1],mo-2)%mo;
        }
    }
    fo(i,1,q) printf("%lld\n",an[i]);
}

【51nod1642】区间欧拉函数

标签:详细   des   amp   sort   维护   www.   rip   str   scanf   

原文地址:https://www.cnblogs.com/sadstone/p/9048642.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!