CF914D Bash and a Tough Math Puzzle 线段树+gcd??奇怪而精妙

嗯~~,好题。。。

用线段树维护区间gcd,按如下法则递归:(记题目中猜测的那个数为x,改动次数为tot)

  1.若子区间的gcd是x的倍数,不递归;

  2.若子区间的gcd不是x的倍数,且没有递归到叶子结点,那么向下递归

  3.若递归到叶子结点,说明这个数需要改动,++tot

  4.若在任意时刻有tot>1,则直接return(不符题意)

#include<cstdio>
#include<iostream>
#define ll long long
#define R register int
#define pc(x) putchar(x)
#define ls (tr<<1)
#define rs (tr<<1|1)
const int M=500010;
using namespace std;
inline int g() {
    R ret=0,fix=1; register char ch; while(!isdigit(ch=getchar())) fix=ch=='-'?-1:fix;
    do ret=ret*10+(ch^48); while(isdigit(ch=getchar())); return ret*fix;
}
int n,m,tot;
int sum[M<<2];
inline int gcd(int a,int b) {return b?gcd(b,a%b):a;}
inline void build(int tr,int l,int r) {
    if(l==r) {sum[tr]=g(); return ;} R md=(l+r)>>1;
    build(ls,l,md),build(rs,md+1,r); sum[tr]=gcd(sum[ls],sum[rs]);
}
inline void update(int tr,int l,int r,int pos,int inc) {
    if(l==r) {sum[tr]=inc; return ;} R md=(l+r)>>1;
    if(pos<=md) update(ls,l,md,pos,inc); else update(rs,md+1,r,pos,inc);
    sum[tr]=gcd(sum[ls],sum[rs]);
}
inline void query(int tr,int l,int r,int LL,int RR,int mod) {
    if(tot>1) return ; if(l==r) { ++tot; return ;} R md=(l+r)>>1;
    if(LL<=md&&sum[ls]%mod) query(ls,l,md,LL,RR,mod); if(RR>md&&sum[rs]%mod) query(rs,md+1,r,LL,RR,mod);
}
signed main() {
    n=g(); build(1,1,n); m=g();
    for(R i=1;i<=m;++i) {
        R k=g(),l=g(),r=g(),mod;
        if(k&1) {
            mod=g(),tot=0,query(1,1,n,l,r,mod); 
            tot>1?(pc('N'),pc('O')):(pc('Y'),pc('E'),pc('S')); pc('
');
        } else update(1,1,n,l,r);
    }
}

2019.04.19

原文地址:https://www.cnblogs.com/Jackpei/p/10738991.html