UESTC 87 Easy Problem With Numbers 线段树区间更新 逆元 分解质因数

UESTC 87 Easy Problem With Numbers


题意:

题意非常简单,给定一个序列 和 M 三种操作

  • 区间内所有元素乘以x
  • 区间内所有元素除以x
  • 查询区间所有元素积取余M

思路:

线段树
问题的关键是区间内所有元素除以x这个操作.
因为要取模,所以不能直接搞.
怎么办?首先我们想到逆元
但是

定理:a存在模p的乘法逆元的充要条件是gcd(a,p) = 1

于是想到了以M的素因子 分解x 最后剩下的数px肯定满足gcd(px,M) = 1

这样我们要维护的东西变成了区间内每个素因子的个数和 与 与M互质的那个数的逆元


#include <bits/stdc++.h>
#define lson num<<1
#define rson num<<1|1
#define gl l,m,lson
#define gr m+1,r,rson
#define PARA int l=1,int r=n,int num=1
#define CLR(a) memset(a,0,sizeof(a))
using namespace std;
typedef long long LL;
const int MAXN = 1e4+100;
int n;
LL MOD;

template <class T>
inline void scan_d(T &ret) {
    char c; ret=0;
    while((c=getchar())<'0'||c>'9');
    while(c>='0'&&c<='9') ret=ret*10+(c-'0'),c=getchar();
}
void ex_gcd(LL a, LL b, LL &x, LL &y)
{
    if(b == 0)
    {
        x = 1;
        y = 0;
        return;
    }
    ex_gcd(b, a % b, x, y);
    LL tmp = x;
    x = y;
    y = tmp - (a / b) * y;
}
LL inv(LL v)
{
    LL x,y;
    ex_gcd(v,MOD,x,y);
    x%=MOD;
    while(x<0) x+=MOD;
    return x;
}

LL mod(LL a, LL b)
{
    if(b < 0) return 0;
      LL ret = 1;
      a %= MOD;
      for (; b; b >>= 1, a = (a * a) % MOD)
            if (b & 1)
                  ret = (ret * a) % MOD;
      return ret;
}

struct Factor
{
    LL fac[12];
    LL ret[12];
    int cnt;
    void init(LL v)
    {
        cnt=0;
        for(LL i=2;i*i<=v;i++)
        {
            if(v%i==0)
                fac[cnt++]=i;
            for(;v%i==0;v/=i);
        }
        if(v!=1)    fac[cnt++]=v;
    }
    void find(LL &v,int f)
    {
        for(int i=0;i<cnt;i++)
        {
            ret[i]=0;
            for(;v&&v%fac[i]==0;v/=fac[i])
                ret[i]=ret[i]+f;
        }
    }
}pf;

struct SegTree
{
    struct Node
    {
        LL l,r;
        LL fac[12],tag[12];
        LL v,tv;
        bool has=0;
        void init(LL a,LL b)
        {
            l=a,r=b;
            v=1;
            tv=1;
            CLR(fac);
            CLR(tag);
            has=0;
        }
        void mark(LL *a,LL b)
        {
            tv*=b;
            tv%=MOD;
            for(int i=0;i<pf.cnt;i++)
            {
                tag[i]+=a[i];
                fac[i]+=a[i]*(r-l+1);
            }
            v=v*mod(b,r-l+1);
            v%=MOD;
            has=1;
        }
        LL count()
        {
            LL ret=v%MOD;
            for(int i=0;i<pf.cnt;i++)
                ret=ret*mod(pf.fac[i],fac[i]),ret%=MOD;
            return ret;
        }
        void show()
        {
            printf("(%lld,%lld):%lld\n",l,r,count());
            printf("v:%lld\n",v);
            for(int i=0;i<pf.cnt;i++)
                printf(" %d",fac[i]);
            puts("");
            printf("tv:%lld\n",tv);
            for(int i=0;i<pf.cnt;i++)
                printf(" %d",tag[i]);
            puts("\n");
        }
    }st[MAXN<<2];
    void pushUp(int num)
    {
        for(int i=0;i<pf.cnt;i++)
            st[num].fac[i]=st[lson].fac[i]+st[rson].fac[i];
        st[num].v=st[lson].v*st[rson].v%MOD;
    }
    void pushDown(int num)
    {
        LL l=st[num].l,r=st[num].r;
        if(l!=r)
        {
            if(st[num].has)
            {
                st[lson].mark(st[num].tag,st[num].tv);
                st[rson].mark(st[num].tag,st[num].tv);
                pushUp(num);
                CLR(st[num].tag);
                st[num].tv=1;
            }
            pushUp(num);
        }
        st[num].has=0;
    }
    void init(PARA)
    {
        int m=l+r>>1;
        st[num].init(l,r);
        if(l==r)
        {
            LL v;
            scan_d(v),pf.find(v,1);
            st[num].mark(pf.ret,v);
        }
        else init(gl),init(gr),pushUp(num);
    }
    void update(int a,int b,LL v,PARA)
    {
        pushDown(num);
        if(a<=l&&r<=b)
            st[num].mark(pf.ret,v);
        else
        {
            int m=l+r>>1;
            if(b<=m)
                update(a,b,v,gl);
            else if(a>m)
                update(a,b,v,gr);
            else
                update(a,b,v,gl),update(a,b,v,gr);
            pushUp(num);
        }
    }
    LL query(int a,int b,PARA)
    {
        pushDown(num);
        if(a<=l&&r<=b)
            return st[num].count();
        else
        {
            int m=l+r>>1;
            LL ret;
            if(b<=m)
                ret=query(a,b,gl);
            else if(a>m)
                ret=query(a,b,gr);
            else
                ret=query(a,b,gl)*query(a,b,gr);
            pushUp(num);
            return ret%MOD;
        }
    }
    void show(PARA)
    {
        int m=l+r>>1;
        st[num].show();
        if(l!=r)
            show(gl),show(gr);
    }
}soul;

bool DEBUG=0;
void debug()
{
    puts("______");
    soul.show();
    puts("______");
}

int main()
{
    if(DEBUG) freopen("v3.txt","w",stdout);
    int T,cas=1;
    scan_d(T);
    while(T--)
    {
        scan_d(n);
        scan_d(MOD);
        pf.init(MOD);
        soul.init();
        int m;
        scan_d(m);
        printf("Case #%d:\n",cas++);
        if(DEBUG)   debug();
        while(m--)
        {
            char s[5];
            scanf("%s",s);
            LL a,b,c;
            scan_d(a);
            scan_d(b);
            if(s[0]=='Q')
                printf("%lld\n",soul.query(a,b));
            else
            {
                scan_d(c);
                int f;
                if(s[0]=='M')
                    pf.find(c,1);
                else
                    pf.find(c,-1),c=inv(c);
                soul.update(a,b,c);
            }
            if(DEBUG)   debug();
        }
    }
    return 0;
}

互联网络程序设计是指在互联网上进行程序开发和设计的过程。UESTC则是我国的一所著名高校——电子科技大学。 互联网络程序设计 uestc包含了两个主要的方面:互联网络和程序设计。互联网络是指将多个计算机网络通过通信链路互相连接起来,实现信息共享和资源共享的网络系统。程序设计是指根据需求和目标,通过编写代码和设计算法,实现计算机程序的过程。 互联网络程序设计 uestc的学习内容主要包括以下几个方面: 1. 网络知识:学习互联网络的基本概念、原理和协议,如TCP/IP协议、HTTP协议等。掌握网络编程的基本技术,能够编写网络应用程序。 2. 数据通信:学习数据通信的基本原理和技术,包括数据传输的方式、数据压缩和加密等。了解网络安全和数据保护的基本知识。 3. 程序设计:学习编程语言和开发工具,如Java、C++和Python等。掌握常用的编程技巧和方法,能够设计和实现复杂的网络应用程序。 4. Web开发:学习Web开发的基本知识和技术,包括HTML、CSS、JavaScript等。能够设计和实现交互式的Web应用程序。 5. 数据库技术:学习数据库的基本原理和技术,如SQL语言和数据库管理系统。能够设计和管理数据库,实现数据的存储和检索。 通过学习互联网络程序设计 uestc,可以掌握互联网应用开发的基本技能,具备设计和实现网络应用程序的能力。这对于目前互联网行业的人才需求来说是非常重要的,也为学生提供了广阔的就业和创业机会。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值