UESTC 1712 Easy Problem With Numbers 除法對和數取模,分解,線段樹

附上神牛原版思路:

如果這個題只有乘法,那麼你肯定會做吧?線段樹更新區間查找區間。
那麼有除法呢?當一個數x和m互質的時候,除以x可以改爲乘以x的逆元。(至於互質的數求逆元用擴展歐幾里德,這個網上可以隨便找到)
但是這題並不能保證除的數與m互質吧?什麼時候x與m不互質呢?就是x與m含有公因子吧?
那麼我們一開始就把m分解,分解出來m有p1,p2,p3,p4...pn等一些因子。
那麼在這個題裏面,每個數x都可以表示成p1^c1*p2^c2*p3^c3.....*pn^cn*A。這裏A就是x去掉p1,p2,p3.。。等因子後的數,A與m就不含公因子了吧,就可以換成A與m的逆元。線段樹裏面呢,就維護c1,c2,c3.....和A的值。乘或除的時候c1,c2.。。就相應加或減。A就直接乘逆元就行了。其實就是一個線段樹懶操作了,更新區間查找區間。
另外這裏求逆元必須用擴展歐幾里得,費馬小定理只適用於mod爲質數。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#define debug puts("======")
typedef long long ll;
using namespace std;
const int maxn=10005;
int n,q;
int tmp;
ll m;
char str[10];
int p[50];
int cnt;
struct Node
{
    int c[11];
    ll a;
}node[maxn<<2];
Node add[maxn<<2];
int no[maxn<<2];
void pre(int u)
{
    cnt=0;
    for(int i=2;i*i<=u;i++) {
        if(u%i==0)
            p[cnt++]=i;
        while(u&&u%i==0) {
            u/=i;
        }
    }
    if(u>1)
        p[cnt++]=u;
}
ll powMod(ll a,ll b)
{
    if(b==0) return 1;
    ll ans=powMod(a,b/2);
    ans=ans*ans%m;
    if(b&1)
        ans=ans*a%m;
    return ans;
}
ll ExGcd(ll a, ll b, ll &x, ll &y)
{
    if(b == 0)
    {
        x = 1;
        y = 0;
        return a;
    }
    ll r = ExGcd(b, a % b, x, y);
    ll t = x;
    x = y;
    y = t - a / b * y;
    return r;
}
void pushUp(int rt)
{
    node[rt].a=node[rt<<1].a*node[rt<<1|1].a%m;
    for(int i=0;i<cnt;i++) {
        node[rt].c[i]=node[rt<<1].c[i]+node[rt<<1|1].c[i];
    }
}
void build(int l,int r,int rt)
{
    no[rt]=0;
    add[rt].a=1;
    for(int i=0;i<cnt;i++)
        add[rt].c[i]=0;
    if(l==r) {
        scanf("%d",&tmp);
        for(int i=0;i<cnt;i++) {
            node[rt].c[i]=0;
            while(tmp && tmp%p[i]==0) {
                tmp/=p[i];
                node[rt].c[i]++;
            }
        }
        node[rt].a=tmp;
        return;
    }
    int m=((l+r)>>1);
    build(l,m,rt<<1);
    build(m+1,r,rt<<1|1);
    pushUp(rt);
}
void pushDown(int l,int r,int rt)
{
    if(no[rt]==0) return;
    no[rt]=0;
    int mm=((l+r)>>1);
    for(int i=0;i<cnt;i++) {
        add[rt<<1].c[i]+=add[rt].c[i];
        add[rt<<1|1].c[i]+=add[rt].c[i];
        node[rt<<1].c[i]+=add[rt].c[i]*(mm-l+1);
        node[rt<<1|1].c[i]+=add[rt].c[i]*(r-mm);
        add[rt].c[i]=0;
    }
    add[rt<<1].a=add[rt<<1].a*add[rt].a%m;
    add[rt<<1|1].a=add[rt<<1|1].a*add[rt].a%m;
    node[rt<<1].a=node[rt<<1].a*powMod(add[rt].a,mm-l+1)%m;
    node[rt<<1|1].a=node[rt<<1|1].a*powMod(add[rt].a,r-mm)%m;
    add[rt].a=1;
    no[rt<<1]=no[rt<<1|1]=1;
}
int num[20];
void update(int L,int R,int c,int l,int r,int rt,int ty)
{
    if(L<=l&&R>=r) {
        int u=c;
        for(int i=0;i<cnt;i++) {
            num[i]=0;
           // debug;
            while(u && u%p[i]==0) {
                u/=p[i];
                num[i]++;
              //  debug;
            }
        }
       // debug;
        no[rt]=1;
        if(ty==0) {
            for(int i=0;i<cnt;i++) {
                add[rt].c[i]+=num[i];
                node[rt].c[i]+=num[i]*(r-l+1);
            }
            add[rt].a=add[rt].a*u%m;
            node[rt].a=node[rt].a*powMod(u,r-l+1)%m;
        }
        else {
            for(int i=0;i<cnt;i++) {
                add[rt].c[i]-=num[i];
                node[rt].c[i]-=num[i]*(r-l+1);
            }
            ll px,py;
            ExGcd(u, m, px, py); //求u的逆元,px爲逆元
            px%=m;
            if(px<0) px+=m;
            add[rt].a=add[rt].a*px%m;
            node[rt].a=node[rt].a*powMod(px,r-l+1)%m;
        }
        return;
    }
    pushDown(l,r,rt);
    int m=(l+r)>>1;
    if(L<=m)
        update(L,R,c,l,m,rt<<1,ty);
    if(R>m)
        update(L,R,c,m+1,r,rt<<1|1,ty);
    pushUp(rt);
}
ll query(int L,int R,int l,int r,int rt)
{
    if(L<=l&&R>=r) {
        ll ans=1;
        for(int i=0;i<cnt;i++) {
            ans=ans*powMod(p[i],node[rt].c[i])%m;
        }
        ans=ans*node[rt].a%m;
        return ans;
    }
    pushDown(l,r,rt);
    ll ans=1;
    int mm=(l+r)>>1;
    if(L<=mm)
        ans=ans*query(L,R,l,mm,rt<<1)%m;
    if(R>mm)
        ans=ans*query(L,R,mm+1,r,rt<<1|1)%m;
    return ans;
}
int main()
{
    int t;
    int a,b,c;
    int cas=1;
    scanf("%d",&t);
    while(t--) {
        scanf("%d%lld",&n,&m);
        pre(m);
        build(1,n,1);
        scanf("%d",&q);
        printf("Case #%d:\n",cas++);
        while(q--) {
            scanf("%s",str);
            if(str[0]=='M') {
                scanf("%d%d%d",&a,&b,&c);
                update(a,b,c,1,n,1,0);
            }
            else if(str[0]=='D') {
                scanf("%d%d%d",&a,&b,&c);
                update(a,b,c,1,n,1,1);
            }
            else {
                scanf("%d%d",&a,&b);
                printf("%lld\n",query(a,b,1,n,1));
            }
        }
    }
    return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章