HDU 3071 Gcd & Lcm game (线段树+素因子分解)

题目链接:

传送门

题意:

给定一个长度为n的序列m次操作,操作的种类一共有三种

  • 查询
    • L :查询一个区间的所有的数的最小公倍数 modp
    • G :查询一个区间的所有的数的最大公约数 modp
  • 修改
    • C :将给定位置的值修改成 x

分析:

首先我们注意一下数据的范围,保证数据不超过100,那么很明显素因子特别少一共只有25个,我们可以用线段树维护一下对应素因子的最大值与最小值。更新的话就是单点更新。由于时间比较紧,我们需要把所有的数压到一个int中去。

Code:

#include <bits/stdc++.h>

using namespace std;

#define lson(id) id<<1
#define rson(id) id<<1|1

int index[110];

const int maxn = 1e5+10;

int p[32];

int cnt ;

void init() {
    memset(index,0,sizeof(index));
    cnt = 0;
    for(int i=2; i<=100; i++) {
        bool tag = 1;
        for(int j=2; j<i; j++) {
            if(i%j==0)
                tag=0;
        }
        if(tag) {
            p[cnt++]=i;
        }
    }
}

int st[30]= {28,25,23,21,20,19,18,17,16,15,14,13,12,11,10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0};

inline int Scan() {   //输入外挂
    int res=0,ch,flag=0;
    if((ch=getchar())=='-')
        flag=1;
    else if(ch>='0'&&ch<='9')
        res=ch-'0';
    while((ch=getchar())>='0'&&ch<='9')
        res=res*10+ch-'0';
    return flag?-res:res;
}

inline int mymin(int x,int y) {
    return min(x&0x70000000,y&0x70000000)|min(x&0x0e000000,y&0x0e000000)|min(x&0x01800000,y&0x01800000)|min(x&0x00600000,y&0x00600000)|((x&0x001fffff)&(y&0x001fffff));
}

inline int mymax(int x,int y) {
    return max(x&0x70000000,y&0x70000000)|max(x&0x0e000000,y&0x0e000000)|max(x&0x01800000,y&0x01800000)|max(x&0x00600000,y&0x00600000)|((x&0x001fffff)|(y&0x001fffff));
}

int trans(int x) {
    int y = 0;
    for(int i=0; i<cnt; i++) {
        int num=0;
        while(x%p[i]==0) {
            x/=p[i];
            num++;
        }
        y|=num<<st[i];
    }
    return y;
}

int calc(int x,int d) {
    int ans = 1%d;
    for(int i=0; i<25; i++) {
        int tmp = x>>st[i];
        for(int j=0; j<tmp; j++)
            ans = ans*p[i]%d;
        x=x^(tmp<<st[i]);
    }
    return ans;
}

struct segtree {
    int mmax[maxn<<2];
    int mmin[maxn<<2];
    void pushup(int id) {
        mmin[id]=mymin(mmin[lson(id)],mmin[rson(id)]);
        mmax[id]=mymax(mmax[lson(id)],mmax[rson(id)]);
    }
    void build(int id,int l,int r) {
        if(l==r) {
            int x=Scan();
            mmin[id]=trans(x);
            mmax[id]=trans(x);
            return;
        }
        int mid = l+r>>1;
        build(lson(id),l,mid);
        build(rson(id),mid+1,r);
        pushup(id);
    }
    void update(int id,int x,int val,int l,int r) {
        if(l==x&&r==x) {
            int tmp = trans(val);
            mmin[id]=tmp;
            mmax[id]=tmp;
            return ;
        }
        int mid = l+r>>1;
        if(mid>=x) update(lson(id),x,val,l,mid);
        else update(rson(id),x,val,mid+1,r);;
        pushup(id);
    }
    int lcm(int id,int l,int r,int x,int y) {
        if(l==x&&r==y) {
            return mmax[id];
        }
        int mid = l+r>>1;
        if(mid>=y) return lcm(lson(id),l,mid,x,y);
        else if(mid<x) return lcm(rson(id),mid+1,r,x,y);
        else return mymax(lcm(lson(id),l,mid,x,mid),lcm(rson(id),mid+1,r,mid+1,y));
    }
    int gcd(int id,int l,int r,int x,int y) {
        if(l==x&&r==y) {
            return mmin[id];
        }
        int mid = l+r>>1;
        if(mid>=y) return gcd(lson(id),l,mid,x,y);
        else if(mid<x) return gcd(rson(id),mid+1,r,x,y);
        else return mymin(gcd(lson(id),l,mid,x,mid),gcd(rson(id),mid+1,r,mid+1,y));
    }
    void output(int id,int l,int r) {
        if(l==r) {
            cout<<mmax[id]<<" ";
            return;
        }
        int mid  = (l+r)>>1;
        output(lson(id),l,mid);
        output(rson(id),mid+1,r);
    }
} T;

int main() {
    init();
    int n,m;
    while(~scanf("%d%d",&n,&m)) {
        T.build(1,1,n);
        for(int i=0; i<m; i++) {
            char s[2];
            scanf("%s",s);
            if(s[0]=='L') {
                int l,r,d;
                l=Scan(),r=Scan(),d=Scan();
                int ans = T.lcm(1,1,n,l,r);
                printf("%d\n",calc(ans,d));
            }
            if(s[0]=='C') {
                int x,val;
                x=Scan(),val=Scan();
                T.update(1,x,val,1,n);
            }
            if(s[0]=='G') {
                int l,r,d;
                l=Scan(),r=Scan(),d=Scan();
                int ans = T.gcd(1,1,n,l,r);
                printf("%d\n",calc(ans,d));
            }
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值