洛谷4140 BZOJ3813 奇数国 欧拉函数 线段树 状压

版权声明:本文为博主原创文章,可以转载但是必须声明版权。 https://blog.csdn.net/forever_shi/article/details/82734820

题目链接
题意:
求区间积的 ϕ 值。

题解:
n u m b e r x + p r o d u c t y = 1 可以转化为 g c d ( n u m b e r , p r o d u c t ) = 1 ,即求 ϕ ( p r o d u c t )
题目保证所有的数都可以表示成前60个质数的若干次方的形式,根据欧拉函数的性质,我们只需要维护区间的product和区间内出现了哪些质因数,product维护区间乘积很好做,但是维护60个质因数的话开60个变量可能可以,但是有可能被卡空间,这里其实可以用一个longlong来状压每个质数是否出现了。然后就是线段树了。

代码:

#include <bits/stdc++.h>
using namespace std;

int n;
long long mod=19961993,ni[70],p[70],cnt;
struct node
{
    int l,r;
    long long ji,p;
}tr[400010],ans;
inline void exgcd(long long a,long long b,long long &x,long long &y)
{
    if(!b)
    {
        x=1;
        y=0;
        return;
    }
    else
    {
        exgcd(b,a%b,y,x);
        y-=a/b*x;
    }
}
inline void pushup(int rt)
{
    tr[rt].ji=tr[rt<<1].ji*tr[rt<<1|1].ji%mod;
    tr[rt].p=tr[rt<<1].p|tr[rt<<1|1].p;
}
inline void build(int rt,int l,int r)
{
    tr[rt].l=l;
    tr[rt].r=r;
    if(l==r)
    {
        tr[rt].ji=3;
        tr[rt].p=2;
        return;
    }
    int mid=(l+r)>>1;
    build(rt<<1,l,mid);
    build(rt<<1|1,mid+1,r);
    pushup(rt);
}
inline void update(int rt,int x,int y)
{
    int l=tr[rt].l,r=tr[rt].r;
    if(l==r)
    {
        long long cur=0;
        for(long long i=1;i<=60;++i)
        {
            if(y%p[i]==0)
            cur|=(1LL<<(i-1));
        }
        tr[rt].p=cur;
        tr[rt].ji=y;
        return;
    }
    int mid=(l+r)>>1;
    if(x<=mid)
    update(rt<<1,x,y);
    else
    update(rt<<1|1,x,y);
    pushup(rt);
}
inline void query(int rt,int le,int ri)
{
    int l=tr[rt].l,r=tr[rt].r;
    if(le<=l&&r<=ri)
    {
        ans.ji=(ans.ji*tr[rt].ji)%mod;
        ans.p|=tr[rt].p;
        return;
    }
    int mid=(l+r)>>1;
    if(le<=mid)
    query(rt<<1,le,ri);
    if(ri>=mid+1)
    query(rt<<1|1,le,ri);
}
int main()
{
    scanf("%d",&n);
    for(int i=2;i<=300;++i)
    {
        int pd=0;
        for(int j=2;j<=sqrt(i);++j)
        {
            if(i%j==0)
            {
                pd=1;
                break;
            }
        }
        if(pd==0)
        {
            p[++cnt]=i;
            if(cnt==60)
            break;
        }
    }
    for(int i=1;i<=cnt;++i)
    {
        long long x,y;
        x=0;
        y=0;
        exgcd(p[i],mod,x,y);
        x=(x%mod+mod)%mod;
        if(!x)
        x+=mod;
        ni[i]=x;
    }
    build(1,1,100000);
    for(int i=1;i<=n;++i)
    {
        int x,y,z;
        scanf("%d%d%d",&x,&y,&z);
        if(x==0)
        {
            ans.p=0;
            ans.ji=1;
            query(1,y,z);
            long long res=ans.ji;
            for(long long j=1;j<=60;++j)
            {
                if(ans.p&(1LL<<(j-1)))
                res=(res*(p[j]-1)%mod*ni[j])%mod;
            }
            printf("%lld\n",res);
        }
        else
        update(1,y,z);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/forever_shi/article/details/82734820