AcWing 246. 区间最大公约数

  • 差分
  • \(\gcd\)

证明:\(\gcd(a_1,a_2,a_3,...,a_n)=\gcd(a_1,a_2-a_1,a_3-a_2,...,a_n-a_{n-1})\).
为方便描述 令 \(c_1=a_1,c_i=a_i-a_{i-1},i>1\).
设其最大公约数为 \(d\) , 则 \(d|a_1,d|a_2,..., --> d|(a_2-a_1)...\)
左边\(=d\);
右边\(=d \times \gcd(c_1/d,c_2/d,...)\)
引理:\(\gcd(c_1/d,c_2/d,...)=1\)
反证法:若 \(\gcd(c_1/d,c_2/d,...)=k,k>1\).

  • \(a_1/d=c_1/d=x \times k\)
  • \(c_2/d=(a_2-a_1)/d=y \times k\)
  • \(a_2/d=(a_1+c_2)/d=x \times k + y \times k=(x+y) \times k\),\(k|a_2\)
  • ...
  • 同理得 \(k|(a_i/d),i \in [1,n]\)

\(\gcd(a_1,a_2,a_3,...,a_n)=d \times k\).
与题设不符,舍去。

所以 \(\gcd(c_1/d,c_2/d,...)=1\)
右边$=d \times \gcd(c_1/d,c_2/d,...)= d = $ 左边。

即证。

Code:

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>

using namespace std;
typedef long long LL;
const int N=5e5+5;

LL a[N],c[N];
int n,m;

LL gcd(LL a,LL b) 
{
    if(b==0) return a;
    else return gcd(b,a%b);
}
#define lc (now<<1)
#define rc (now<<1|1)
LL sum[4*N],d[4*N];
void Update(int now,int pos,LL key,int l,int r)
{
    if(l==r&&l==pos) {
        sum[now]+=key;
        d[now]+=key;
        return;
    }
    int mid=(l+r)>>1;
    if(pos<=mid) Update(lc,pos,key,l,mid);
    else Update(rc,pos,key,mid+1,r);

    sum[now]=sum[lc]+sum[rc];
    d[now]=gcd(d[lc],d[rc]);
}

LL QuerySum(int now,int pos,int l,int r)
{
    if(r<=pos) return sum[now];
    int mid=(l+r)>>1;
    LL res=QuerySum(lc,pos,l,mid);
    if(pos>=mid+1) res+=QuerySum(rc,pos,mid+1,r);
    return res;
}

LL QueryGcd(int now,int x,int y,int l,int r)
{
    if(x<=l&&r<=y) return d[now];
    int mid=(l+r)>>1;
    LL res=0;
    if(x<=mid) res=gcd(res,QueryGcd(lc,x,y,l,mid));
    if(y>=mid+1) res=gcd(res,QueryGcd(rc,x,y,mid+1,r));
    return res;
}


int main()
{
    int i;
    int x,y;
    LL z;
    char opt;
    scanf("%d%d",&n,&m);
    for(i=1;i<=n;i++) {
        scanf("%lld",&a[i]);
        c[i]=a[i]-a[i-1];
        Update(1,i,c[i],1,n);
    }
    while(m--) {
        for(opt=getchar();opt!='C'&&opt!='Q';opt=getchar());
        scanf("%d%d",&x,&y);
        if(opt=='Q') printf("%lld\n",abs(gcd(QueryGcd(1,x+1,y,1,n),QuerySum(1,x,1,n))));
        else {
            scanf("%lld",&z);
            Update(1,x,z,1,n);
            if(y+1<=n) Update(1,y+1,-z,1,n);
        }
    }
    return 0;
}
posted @ 2020-11-28 21:21  cjlworld  阅读(107)  评论(0编辑  收藏  举报