欧拉函数 线段树 状压 奇数国

让我们一起来%forever_shi神犇

题意:求区间积的 ϕ \phi 值。

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

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int mod=19961993;
int m,num;
ll p[1000];
ll inv[1000];
struct node
{
    int l,r;
    ll mul,p;
}tr[1001000],ans;
ll ksm(ll q,ll w)
{
    ll h=1;
    while(w)
    {
        if(w&1)
            h=h*q%mod;
        q=q*q%mod;
        w>>=1;
    }
    return h;
}
void pushdown(int rt)
{
    tr[rt].mul=(tr[rt*2].mul%mod*tr[rt*2+1].mul%mod)%mod;
    tr[rt].p=tr[rt*2].p|tr[rt*2+1].p; 
} 
void build(int rt,int l,int r)
{
    tr[rt].l=l;
    tr[rt].r=r;
    if(l==r)
    {
        tr[rt].mul=3;
        tr[rt].p=2;
        return;
    }
    int mid=(l+r)/2;
    build(rt*2,l,mid);
    build(rt*2+1,mid+1,r);
    pushdown(rt);
}
void update(int rt,int x,int y)
{
    int l=tr[rt].l;
    int r=tr[rt].r;
    if(l==r)
    {
        ll now=0;
        for(ll i=1;i<=60;++i)
            if(y%p[i]==0)
                 now+=(1LL<<(i-1));
        tr[rt].p=now;
        tr[rt].mul=y;
        return;
    }
    int mid=(l+r)/2;
    if(x<=mid)
        update(rt*2,x,y);
    else
        update(rt*2+1,x,y);
    pushdown(rt);
}
void query(int rt,int L,int R)
{
    int l=tr[rt].l;
    int r=tr[rt].r;
    if(l>=L&&r<=R)
    {
        ans.mul=(ans.mul%mod*tr[rt].mul%mod)%mod;
        ans.p|=tr[rt].p;
        return;
    }	
    int mid=(l+r)/2;
    if(L<=mid)
        query(rt*2,L,R);
    if(R>=mid+1)
        query(rt*2+1,L,R);
}
int main()
{
    scanf("%d",&m);
    for(int i=2;i<=300;++i)
    {
        int sum=0;
        for(int j=1;j<=i;++j)
            if(i%j==0)
                sum++;
        if(sum<=2)
            p[++num]=i;
        if(num==60)
            break;
    }
    for(int i=1;i<=60;++i)
        inv[i]=ksm(p[i],mod-2);
    build(1,1,100000);
    for(int i=1;i<=m;++i)
    {
        int x,y,z;
        scanf("%d%d%d",&x,&y,&z);
        if(x==0)
        {
            ans.mul=1;
            ans.p=0;
            query(1,y,z);
            ll res=ans.mul;
            for(int j=1;j<=60;++j)
                if(ans.p&(1LL<<(j-1)))
                    res=(res%mod*(p[j]-1)%mod*inv[j]%mod)%mod;
            printf("%lld\n",res);
        }
        else 
            update(1,y,z);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/wddwjlss/article/details/82867402
今日推荐