题目描述:
TL:1S ML:256MB
【Description】
有N个整数,kAc会对它们做Q次修改。
每次修改指的是对所有数加一个整数(可正可负)
每修改一次后,他想知道当前所有数的最大公约数是多少。
【Input】
第一行两个整数N, Q
接下来N行,每行一个整数,表示这N个数的初始值。
接下来Q行,每行一个整数,表示这Q个操作。第i个数表示这一次操作是增加了多少。
【Output】
共Q行,表示进行完第i次操作后,所有数的最大公约数
【Sample Input】
3 2
1 -5 7
-1
1
【Sample Output】
6
1
【Hint】
对于40%:N, Q <= 1000
对于70%:N, Q <= 40000
对于100%:N, Q <= 100000,所有数的绝对值始终小于等于10^16
在这里,我们认为任意非负整数x跟0的最大公约数都是x
40%的数据就是一个暴力,注意留坑的是不能除以0
可以看出这是个o(n)的题目
这道题目时雨加减有关的
有个欧几里得定理
gcd(a,b)=gcd(a,a-b)
这个证明非常好想
毕竟是整除的
那么现在想差值
无论减去多少,差值总是不变的
•gcd(a[1], a[2]) = gcd(a[1], a[2] – a[1]) •gcd(a[2], a[3]) = gcd(a[2], a[3] – a[2]) •gcd(a[1], a[2], a[3]) = gcd(a[1], a[2] –a[1], a[3] – a[2]) • •gcd(a[1], … , a[n]) = gcd(a[1], a[2] –a[1] … ,a[n] – a[n – 1]) 这样子每次只算a1的值就可以了!
你要的O(n)
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long ll;
const int maxn=100005;
ll a[maxn];
ll n,q,t1,t2;
ll gcd(ll xx,ll yy)
{
if(yy==0)
return xx;
else
return gcd(yy,xx%yy);
}
ll cgcd(ll xxx,ll yyy)
{
if(xxx==0)
return yyy;
if(yyy==0)
return xxx;
xxx=abs(xxx),yyy=abs(yyy);
return gcd(xxx,yyy);
}
ll calc(ll x)
{
int cur=1;
while((a[cur]+x)==0) cur++;
if(cur==n+1) return 0;
else
{
ll res=cgcd(a[cur]+x,a[cur+1]+x);
for(ll i=cur+2;i<=n;i++)
{
res=cgcd(res,a[i]+x);
}
return res;
}
}
int main()
{
freopen("gcd.in","r",stdin);
freopen("gcd.out","w",stdout);
cin>>n>>q;
for(int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
}
if(n<=1000&&q<=1000)
{
ll sum=0;
for(int i=1;i<=q;i++)
{
scanf("%lld",&t1);
sum+=t1;
ll nw=calc(sum);
printf("%lld\n",nw);
}
return 0;
}
else
{
ll ans=cgcd(a[2]-a[1],a[3]-a[2]);
for(int i=4;i<=n;i++)
ans=cgcd(ans,a[i]-a[i-1]);
ll sum=0;
for(int i=1;i<=q;i++)
{
scanf("%lld",&t1);
sum+=t1;
ll w=cgcd(ans,a[1]+sum);
printf("%lld\n",w);
}
return 0;
}
}