POI Knights

题目链接

题目大意

n(n100) n ( n ≤ 100 ) 个二元组描述了一个骑士的行进方式,遵从如下规则:

若二元组为 (a,b) ( a , b ) ,则骑士从 (x,y) ( x , y ) 出发可以到达 (x+a,y+b) ( x + a , y + b ) (xa,yb) ( x − a , y − b )

两个二元组集合是等价的当且仅当有一个从 (0,0) ( 0 , 0 ) 出发的骑士,经过任意次行进,通过这两组二元组所能到达的格子完全相同。
可以看出对于任何一个二元组集合,都有一个大小为2的集合与它等价,求这个大小为2的集合。

思路

首先可以证明这个集合肯定存在:

将这些行走方式看做一个个向量,则一定存在一组基底可以通过线性组合表示这些向量,因为是二维空间,故基底的个数为2

然后考虑如何求这一组基底。
找一组简单的数据画图可以发现,对于一个固定的横坐标,这一列上所有的点的纵坐标的间距是相等的,同时更换横坐标时这个间距不变。又可以看出,只有某些横坐标才会有点,并且这些横坐标的间距也是相等的。
先考虑求纵坐标上的间距,设间距为 y y 有如下推导:
设两向量分别为(a1,b1),(a2,b2)" role="presentation">(a1,b1),(a2,b2),两向量系数分别为 t1,t2 t 1 , t 2
先考虑最简单的情景,该点在 y y 轴上,我们求(0,0)" role="presentation">(0,0)点正上方的那个点。则可以列出如下式子。

t1a1+t2a2=0t1b1+t2b2=y { t 1 a 1 + t 2 a 2 = 0 t 1 b 1 + t 2 b 2 = y
将第一个式子移项得
t1a1a2=t2 t 1 a 1 a 2 = − t 2
t2 t 2 显然是整数(骑士是不是肯定不能走半步),故
a2  t1a1 a 2 | t 1 a 1
这个式子的形式并不能说明什么,我们两边同除 gcd(a1,a2) gcd ( a 1 , a 2 ) ,得
a2gcd(a1,a2)  t1a1gcd(a1,a2) a 2 gcd ( a 1 , a 2 ) | t 1 a 1 gcd ( a 1 , a 2 )
a1=a1gcd(a1,a2),a2=a2gcd(a1,a2) a 1 ′ = a 1 gcd ( a 1 , a 2 ) , a 2 ′ = a 2 gcd ( a 1 , a 2 ) ,可得 gcd(a1,a2)=1 gcd ( a 1 ′ , a 2 ′ ) = 1 ,故
a2  t1 a 2 ′ | t 1
t1=ka2gcd(a1,a2) t 1 = k a 2 gcd ( a 1 , a 2 )
同理 t2=ka1gcd(a1,a2) t 2 = k a 1 gcd ( a 1 , a 2 ) ,此处 t1,t2 t 1 , t 2 异号。
带回原式得
ka1b2a2b1gcd(a,b)=y k ∗ a 1 b 2 − a 2 b 1 gcd ( a , b ) = y
正上方的点, k=1 k = 1 ,所以有 y=a1b2a2b1gcd(a1,a2) y = a 1 b 2 − a 2 b 1 gcd ( a 1 , a 2 )
求出了这个间距,不禁让我们有了一些想法。

能不能将任意的两个向量(非共线),找到另两个等价向量,满足其中一个与 y y 轴平行?

答案是可以的。怎么做呢?
其中一个向量肯定是(0,a1b2a2b1gcd(a1,a2))" role="presentation">(0,a1b2a2b1gcd(a1,a2)),另一个是用来控制横坐标改变和随之而来的纵坐标改变的。
这个向量是 (gcd(a1,a2),y) ( gcd ( a 1 , a 2 ) , y ) ,现在我们来求这个 y y
这个向量的横坐标可以看成是由最初的两个向量按比例缩放而成的,故纵坐标也应该是它按比例缩放的。
让我们想起了一个熟悉的式子。
a1x+a2y=gcd(a1,a2)" role="presentation">a1x+a2y=gcd(a1,a2)
熟悉不?其中 x,y x , y 就是缩放的比例。扩展欧几里得即可求解。
则第二个坐标为 b1x+b2y b 1 x + b 2 y

由此我们得到了一个算法:每次找到两个向量,把其中一个变成与 y y 轴平行,另一个继续扔回向量堆中。继续重复算法,直到只剩一个不与y" role="presentation">y轴平行。此时有一大堆和 y y 轴平行的向量,我们对其纵坐标取一个gcd" role="presentation">gcd,即是最终的答案之一,另一个就是剩下的那个没有做此算法的向量。

代码
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define pa pair
#define INF 0x3f3f3f3f
#define inf 0x3f
#define fi first
#define se second
#define mp make_pair
#define ll long long
#define ull unsigned long long
#define pb push_backusing namespace std;inline ll read()
{long long f=1,sum=0;char c=getchar();while (!isdigit(c)) {if (c=='-') f=-1;c=getchar();}while (isdigit(c)) {sum=sum*10+c-'0';c=getchar();}return sum*f;
}
const int MAXN=110;
ll exgcd(ll a,ll b,ll &x,ll &y)
{if (!b){x=1,y=0;return a;}ll tmp,ret;ret=exgcd(b,a%b,x,y);tmp=x;x=y;y=tmp-a/b*y;return ret;
}
int _gcd(int a,int b)
{if (!b) return a;return _gcd(b,a%b);
}
int a[MAXN],b[MAXN];
int main()
{int n;scanf("%d",&n);for (int i=1;i<=n;i++)scanf("%d%d",&a[i],&b[i]);for (int i=2;i<=n;i++){ll x,y;ll gcd=exgcd(a[i-1],a[i],x,y);ll tmpa1=0,tmpb1=(a[i-1]*b[i]-a[i]*b[i-1])/gcd;ll tmpa2=gcd,tmpb2=b[i-1]*x+b[i]*y;a[i-1]=tmpa1,b[i-1]=tmpb1;a[i]=tmpa2,b[i]=tmpb2; }int nb=b[1];for (int i=2;icout<<0<<' '<" "<return 0;
}


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部