Asia Tsukuba 2016-2017 I - Skinny Polygon
Skinny Polygon
题意:给出宽高分别为xbb,ybb的矩形,要求一个顶点在格点的三角形或四边形(可以凹四边形)的面积小于25000,同时满足矩形各边上皆有点
二维平面上,三点坐标分别为 ( 0 , 0 ) , ( a , b ) , ( c , d ) (0,0), (a, b), (c, d) (0,0),(a,b),(c,d)的三角形的面积可以表示为 ∣ a d − b c ∣ 2 \frac{|ad-bc|}{2} 2∣ad−bc∣ (叉积的应用)
格点多边形面积公式: S = 内 部 点 数 + 边 界 点 数 2 − 1 S = 内部点数+\frac{边界点数}{2} - 1 S=内部点数+2边界点数−1 (皮克定理)
一些特殊情况:
-
当xbb和ybb互质的时候,根据扩展欧几里得原理,对于 a = x b b , b = y b b a=xbb,b = ybb a=xbb,b=ybb , 有: ∣ a d − b c ∣ = 1 |ad-bc| = 1 ∣ad−bc∣=1
即存在三角形面积为 1 2 \frac{1}{2} 21, 符合条件
-
当 x b b = = y b b xbb==ybb xbb==ybb的时候, 即最外面这个大框为正方形时,取 ( 0 , 0 ) , ( 1 , 1 ) , ( x b b − 1 , y b b ) , ( x b b , y b b − 1 ) (0,0),(1, 1),(xbb-1, ybb),(xbb, ybb-1) (0,0),(1,1),(xbb−1,ybb),(xbb,ybb−1)四个点构成的凹四边形面积为1
考虑将上述两种特殊情况扩展到一般,
-
对于情况1,直接还是扩欧,存在 ∣ a d − b c ∣ = g c d ( a , b ) |ad-bc| = gcd(a,b) ∣ad−bc∣=gcd(a,b) 即三角形面积为 g c d ( a , b ) 2 \frac{gcd(a, b)}{2} 2gcd(a,b)
-
对于情况2,考虑仍取 ( 0 , 0 ) , ( x b b − 1 , y b b ) , ( x b b , y b b − 1 ) (0,0), (xbb-1, ybb),(xbb, ybb-1) (0,0),(xbb−1,ybb),(xbb,ybb−1) 这样三个点,剩下一个点取在矩形对角线最接近 ( 0 , 0 ) (0,0) (0,0) 的格点上,即为 ( x b b g , y b b g ) (\frac{xbb}{g}, \frac{ybb}{g}) (gxbb,gybb) ,凹四边形面积为 x b b g + y b b g 2 \frac{\frac{xbb}{g} +\frac{ ybb}{g}}{2} 2gxbb+gybb (皮克定理或转化为三角形叉积)
在这两种情况中取较小便满足条件
扩展欧几里得 求ax+by=gcd(a,b)的解
要求
a
d
−
b
c
=
g
c
d
(
a
,
b
)
ad - bc = gcd(a, b)
ad−bc=gcd(a,b)
A
=
a
(
x
b
b
)
,
B
=
b
(
y
b
b
)
,
X
=
d
,
Y
=
−
c
A
X
+
B
Y
=
g
c
d
(
A
,
B
)
k
x
=
B
/
g
c
d
k
y
=
A
/
g
c
d
通
解
X
=
X
′
+
k
x
×
n
,
Y
=
Y
′
+
k
y
×
n
A = a(xbb), B = b(ybb), X = d, Y= -c\\ AX+BY = gcd(A, B)\\ kx = B /gcd\\ ky = A/gcd\\ 通解 X = X' + kx \times n, Y = Y' + ky \times n
A=a(xbb),B=b(ybb),X=d,Y=−cAX+BY=gcd(A,B)kx=B/gcdky=A/gcd通解X=X′+kx×n,Y=Y′+ky×n
好像直接求出来就满足,所以代码中这段替换其实不知道对不对(?
#include "bits/stdc++.h"
using namespace std;
typedef long long ll;
ll ex_gcd(ll a, ll b, ll &x, ll &y) {
if (b == 0) {
x = 1;
y = 0;
return a;
}
ll d = ex_gcd(b, a % b, x, y);
ll temp = x;
x = y;
y = temp - a / b * y;
return d;
}
signed main() {
ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
ll T;
cin >> T;
while (T--) {
ll x, y;
cin >> x >> y;
ll xx, yy;
ll d = ex_gcd(x, y, xx, yy);
if ((x / d + y / d) / 2 <= 25000) {
cout << 4 << endl;
cout << 0 << " " << 0 << endl;
cout << x - 1 << " " << y << endl;
cout << x / d << " " << y / d << endl;
cout << x << " " << y - 1 << endl;
continue;
}
ll kx = -y / d;
ll ky = -x / d;
// cerr << xx << " " << yy << " " << kx << " " << ky << endl;
ll ansx = xx, ansy = yy;
ll i = 0;
while (1) {
if ((xx + kx * i) * (yy + ky * i) <= 0
&& (abs(xx + kx * i) <= y) && (abs(yy + ky * i) <= x)) {
ansx = xx + kx * i, ansy = yy + ky * i;
break;
}
if ((xx - kx * i) * (yy - ky * i) <= 0
&& (abs(xx -kx * i) <= y) && (abs(yy - ky * i) <= x)) {
ansx = xx - kx * i, ansy = yy - ky * i;
break;
}
++i;
}
cout << 3 << endl;
cout << 0 << " " << 0 << endl;
cout << x << " " << y << endl;
cout << abs(ansy) << " " << abs(ansx) << endl;
}
return 0;
}