【Codecraft-18 and Codeforces Round #458 (Div. 1 + Div. 2, combined) D】Bash and a Tough Math Puzzle...

【链接】 我是链接,点我呀:)
【题意】


在这里输入题意

【题解】


对于1操作
令len = r-l+1
等价于查找l..r这个范围内x的倍数的个数是否大于等于len-1
也即l..r这个范围内不是x的倍数的个数小于等于1个
(因为如果改的话,肯定是把那个数字改成x,其他n-1个数必须是x的倍数,只有这样gcd才会为x
(不用改的情况不一定里面就一定有x,但肯定都是x的倍数
(所以我们改的时候,实际上是一个贪心的过程,就强行把那个不是x的倍数的数改成x
(或者是虽然都是x的倍数,但gcd比x大,那么就任意把一个数字改成x就好了,gcd肯定就变成x了
(这样加上"其他n-1个数字都是x的倍数"这个限制,整体的gcd就是x了

这个可以通过建立线段树来实现。
因为gcd有交换律。
所以合并的时候,只要把左边的gcd和右边的gcd一起求一个gcd就行了。

这样。我们在某个区间内。
设l..mid的gcd为xx
设mid+1..r的gcd为yy
如果gcd(xx,x)!=x 且 gcd(yy,x)!=x
也就是说左右两个子区间的gcd都不是x的倍数。
那么就直接返回无解。
(因为这就表示这两个区间分别有一个数字不是x的倍数,即不是x的倍数的个数>1,所以无解

如果gcd(xx,x)==x且gcd(yy,x)==x
就说明左右两个区间的gcd都是x的倍数。
那么这两个区间里面的数字肯定都是x的倍数。
也可以直接返回。

否则如果gcd(xx,x)!=x那么就往左区间继续递归。
如果gcd(yy,x)!=x那么就往右区间继续递归。
中间如果发现不是x的倍数的个数超过了1就直接退出

2操作就是线段树的单点更新。

【代码】

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define rson m+1,r,rt<<1|1
#define lson l,m,rt<<1
using namespace std;
const int N=5e5+7;
int n,i,j,a[N],tr[N<<2],now,x;

void build(int l=1,int r=n,int rt=1)
{
    if(l==r){
        tr[rt]=a[l];
        return;
    }
    int m=(l+r)>>1;
    build(lson);
    build(rson);
    tr[rt]=__gcd( tr[rt<<1] , tr[rt<<1|1]);
}

void query(int L,int R,int l=1,int r=n,int rt=1)
{
    if (now>1) return;
    int m=(l+r)>>1;
    if(L<=l&&r<=R)    {
        if (l==r){
            if (__gcd(tr[rt],x)!=x) now++;
            return;
        }
        int xx = __gcd(tr[rt<<1],x),yy = __gcd(tr[rt<<1|1],x);
        if (xx!=x && yy!=x){
            now+=2;
            return;
        }else if (xx==x && yy==x) return;
        if (xx!=x) query(L,R,lson);
        if (yy!=x) query(L,R,rson);
        return;
    }
    if (L<=m) query(L,R,lson);
    if (m<R) query(L,R,rson);
}

void updata(int p,int num,int l = 1,int r = n,int rt = 1){
    if (l==r){
        a[l] = num;
        tr[rt] = a[l];
        return;
    }
    int m = (l+r)>>1;
    if (p<=m)
        updata(p,num,lson);
    else
        updata(p,num,rson);
    tr[rt]=__gcd( tr[rt<<1] , tr[rt<<1|1]);
}

int main()
{
    #ifdef LOCAL_DEFINE
        freopen("rush_in.txt", "r", stdin);
    #endif
    ios::sync_with_stdio(0),cin.tie(0);

    cin >>n;
    for (int i = 1;i <= n;i++) cin >>a[i];
    build();
    int Q;
    cin >> Q;
    while (Q--){

        int ope;
        cin >>ope;
        if (ope==2){
            int i,y;
            cin >> i >> y;
            updata(i,y);
        }else{
            int l,r;
            cin >> l >> r >> x;
            now = 0;
            query(l,r);
            if (now>1){
                cout<<"NO"<<endl;
            }else{
                cout <<"YES"<<endl;
            }
        }
    }
    return 0;
}

转载于:https://www.cnblogs.com/AWCXV/p/8329650.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值