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('\n'); } else update(1,1,n,l,r); } }
2019.04.19