p3412 [POI2005]SKO-Knights

时间:2023-12-10 17:20:26

传送门

分析

p3412 [POI2005]SKO-Knights图1

我们假设我们现在有两个向量(2,3)和(4,2),将他们所能到达的点在几何画板上画出来,再将这些点用红线连起来,在将横坐标相同的点用蓝线连起来便能得到图1,就此我们可以发现可以用绿色的两个向量取代之前的两个向量,并且发现有一个向量可以是(0,B)的形式。在发现这个之后我们现在的任务便是求出新向量和原向量的关系了,见下边的推导:

p3412 [POI2005]SKO-Knights

p3412 [POI2005]SKO-Knights

所以我们可以将任何两个向量转变成一个在y轴的向量和一个其它向量。所以我们只需要不断的将向量转变到y轴上使得最终至多一个向量不再y轴上就行了。注意在y轴上的向量我们可以通过取它们的gcd将它们合并成一个向量。详见代码。

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cctype>
#include<cmath>
#include<cstdlib>
#include<queue>
#include<ctime>
#include<vector>
#include<set>
#include<map>
#include<stack>
using namespace std;
int a[],b[];
inline void exgcd(int a,int b,int &x,int &y){
if(b==){
x=;
y=;
return;
}
exgcd(b,a%b,x,y);
int z=x;
x=y;
y=z-(a/b)*y;
return;
}
int main(){
int n,m,i,j,k,x,y;
scanf("%d",&n);
for(i=;i<=n;i++){
scanf("%d%d",&a[i],&b[i]);
}
int a1,b1,a2,b2;
if(!a[]){
a1=a[];
b1=b[];
b2=b[];
}else if(!a[]){
a1=a[];
b1=b[];
b2=b[];
}else {
a1=__gcd(a[],a[]);
exgcd(a[]/a1,a[]/a1,x,y);
b1=b[]*x+b[]*y;
b2=abs(b[]*a[]-b[]*a[])/a1;
}
for(i=;i<=n;i++){
if(!a1){
a1=a[i];
b2=__gcd(b2,b1);
b1=b[i];
}else if(!a[i]){
b2=__gcd(b2,b[i]);
}else {
int be=a1,be2=b1;
a1=__gcd(a1,a[i]);
exgcd(be/a1,a[i]/a1,x,y);
b1=b1*x+b[i]*y;
b2=__gcd(b2,abs(be2*a[i]-b[i]*be)/a1);
}
}
cout<<a1<<' '<<b1<<endl<<<<' '<<b2<<endl;
return ;
}