计算
- 基础:
int gcd(int a,int b){return a%b==0?b:gcd(b,a%b);}
int lcm(int a,int b){return a/gcd(a,b)*b;}
- 打表&&O(nm)内:
for (int i = 1; i <= n; i ++)
for (int j = 1; j <= m; j ++)
if (!Gcd[i][j])
for (int k = 1; k * i <= n && k * j <= m; k ++)
Gcd[k * i][k * j] = k, A[k * i][k * j] = i * j * k;
//Gcd[i][j]:gcd(i,j)
//A[i][j]:lcm(i,j)
性质
-
gcd(a,b)=gcd(b,a%b)
-
gcd(a,b)=gcd(a,b+a*k) k为任意整数
由:gcd(a,b)=gcd(a,b-a)
扩展:gcd(a[1],a[2],…,a[n])=gcd(a[1],a[2]-a[1],…,a[n]-a[n-1])
-
gcd(a,b)=gcd(a,b,a*k) k为任意整数
-
gcd(a,b,c,…z)=gcd(a,b+k*a,c,…z) k为任意整数
题目
题目速递: https://vjudge.net/contest/409019#problem/L
题意:设C=lcm(a,b),且(a,b)下一步可达(a,b+C)或者(a+C,b)
给一点(A,B),问能有多少个可能出发点。
突破点:可达的点的坐标的gcd必定相等。【上面的第二条性质】
据此可求出回到上一点需要的C,一直计算下去直到不符合题目条件就break。
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=1e6+6;
#define ll long long
int main(){
int T;
cin>>T;
int t=0;
while(T--){
t++;
ll a,b;
scanf("%lld%lld",&a,&b);
int ans=1;
ll gcd=__gcd(a,b);
while(1){
if(a>b)swap(a,b);
if(a<=0)break;
if(a*b%(gcd+a)==0){
ll c=a*b/(gcd+a);
b=b-c;
if(__gcd(a,b)!=gcd)break;
ans++;
}else break;
}
cout<<"Case #"<<t<<": "<<ans<<"\n";
}
}