There is a beautiful garden in Marjar University. Recently, Edward, the headmaster of Marjar University, decided to build a garden water sprinkler system. The system consists of three sprinklers.
Assuming that Marjar University is an infinite plane, the garden is a circle whose center is at (X0, Y0) with radius R. Now, Edward has already determined the position for two sprinklers at (X1, Y1) and (X2, Y2). He needs to choose the position for the last sprinkler. Here are some conditions to be satisfied:
- The three sprinklers should not in the same line.
- The last sprinkler should be located inside or on the boundary of the garden.
- The coordinates of the sprinklers must be integers.
- Twice the area of the triangle that the three sprinklers form should equals S.
Under these conditions, Edward wants to know the number of possible positions for the last sprinkler. Please write a program to help him!
Input
There are multiple test cases. The first line of input contains an integer T indicating the number of test cases. For each test case:
The first line contains an integer S (1 <= S <= 108). The next line contains three integers X0, Y0 and R (1 <= R <= 108). The last line contains four integers X1, Y1, X2and Y2.
It is guaranteed that the absolute value of all input coordinates will not exceed 108 and the positions of the two existing sprinklers are different.
Output
For each test case, output the number of possible positions.
Sample Input
1 4 0 0 4 -1 0 1 0
Sample Output
14
Hint
In the sample test case, the possible positions for the last sprinkler are: (-3, 2), (-2, 2), (-1, 2), (0, 2), (1, 2), (2, 2), (3, 2), (-3, -2), (-2, -2), (-1, -2), (0, -2), (1, -2), (2, -2), (3, -2).
题意:给出一个圆,和圆内(上)两个不同的点,你要在圆内(上)找到第三个点(x,y)使得三个点形成的三角形的面积的两倍是S,而且x和y要是整数,问有多少个满足要求的点。
思路:其实题目本身不难,很多人都能想到,正因为这样,这题的正确率才落到2%..... 第一步是先将所有的点都平移一下吧,让圆的圆心在(0,0),然后我们把第三个点设为(x,y),那么现在有三个点的坐标,我们可以直接用叉乘来列出等式,有形如这样的|ax + by+c| = S, 也就是找
ax + by + c - S = 0的整数解和ax + by + c + S = 0的整数解。 其中x * x + y * y <= R * R .
那么我们把图画出来,就是一条直线与圆的关系,如果直线与圆相离,整数解为0. 如果是相切和相交,我们先用欧几里得算法求出一个可行解,然后在看有多少个解在圆内就行了。
思路上就仅仅上面说的.....但是题目给的数有点大,运算的过程中频频溢出.....于是我用了Java .Orz. 用了Java发现不知道怎么求直线和圆的交点,因为通常解法是联立方程求解,会有一个取根号的运算....Java大数不知道怎么取根号....二分也行吧。不过我是先求出圆心到直线的垂心,然后就二分分别求出左交点的x坐标和右交点的x坐标,然后用扩展欧几里得求出可行解后,看有多少个解就行了......中间有好多边界没处理好,所以错了好多次.....如果自己做的时候觉得毫无破绽但是WA的,可以先写一个暴力的程序然后看看对不对,小一点的数据可以的话,一般都是可以的。另外,这个题目大概4W多组数据吧
具体的可以看代码,不过以前没怎么用过Java写题,可能下面的代码会很难看.....
代码:
import java.io.*;
import java.util.*;
import java.math.*;
public class Main {
public static void main(String [] args) throws IOException
{
Main body = new Main();
Solver solver = body.new Solver();
}
public class Solver
{
StreamTokenizer cin = new StreamTokenizer(new BufferedReader(
new InputStreamReader(System.in)));
PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
BigInteger x0,y0,x1,y1,x2,y2,R,S;
BigInteger sqrR,sqrb,sqra,sqrc;
long SS,x00,y00,x11,y11,x22,y22,RR;
int BruteForce()
{
int ans = 0;
long aa = a.longValue(), bb = b.longValue(), cc = c.longValue();
if (aa == 0) {
if (cc % bb != 0) return 0;
else {
long y = cc / bb;
for(long x = -R.longValue(); x <= R.longValue(); ++x) {
if (x*x + y*y <= sqrR.longValue()) ++ans;
}
}
} else if (b.equals(ZERO())) {
if (cc % aa != 0) return 0;
else {
long x = cc / aa;
for(long y = -R.longValue(); y <= R.longValue(); ++y) {
if (x*x+y*y<=sqrR.longValue()) ++ans;
}
}
} else {
for(long x = -R.longValue(); x <= R.longValue(); ++x) {
if ((aa*x+cc)%bb != 0) continue;
long y = aa*x + cc; y /= -bb;
if (x*x + y*y <= sqrR.longValue()) {
++ans;
System.out.println(x);
}
}
}
return ans;
}
void input() throws IOException
{
cin.nextToken();
S = valueOf((long)cin.nval);
cin.nextToken();
x00 = (long)cin.nval;
cin.nextToken();
y00 = (long)cin.nval;
cin.nextToken();
R = valueOf((long)cin.nval);
cin.nextToken();
x11 = (long)cin.nval;
cin.nextToken();
y11 = (long)cin.nval;
cin.nextToken();
x22 = (long)cin.nval;
cin.nextToken();
y22 = (long)cin.nval;
x11 -= x00; y11 -= y00;
x22 -= x00; y22 -= y00;
}
final BigInteger ZERO() { return BigInteger.ZERO; }
final BigInteger ONE() { return BigInteger.ONE; }
final BigInteger TWO() { return ONE().add(ONE()); }
final BigInteger valueOf(long x) { return BigInteger.valueOf(x); }
void gcd(BigInteger a,BigInteger b,BigInteger [] d, BigInteger [] x,BigInteger[] y)
{
if (b.equals(BigInteger.ZERO)) { d[0] = a; x[0] = BigInteger.ONE; y[0] = BigInteger.ZERO; }
else {
gcd(b,a.remainder(b),d,y,x);
y[0] = y[0].subtract(x[0].multiply(a.divide(b)));
}
}
final BigInteger sqr(BigInteger x) { return x.multiply(x); }
BigInteger m,sqrRb,red;
final void GetBound(BigInteger [] LL,BigInteger [] RR)
{
BigInteger l = R.negate(),r = m;
BigInteger x = ZERO(), dis = ZERO();
BigInteger ac2 = a.multiply(c).multiply(TWO());
if (!red.equals(ZERO())) {
if (ac2.negate().compareTo(ZERO()) < 0) r = r.subtract(ONE());
}
while (l.compareTo(r) <= 0) {
x = (l.add(r)).divide(TWO());
dis = sqra.add(sqrb).multiply(sqr(x));
dis = dis.add(x.multiply(ac2));
dis = dis.add(sqrc);
if (dis.compareTo(sqrRb) > 0) l = x.add(ONE());
else r = x.subtract(ONE());
}
LL[0] = l;
l = m; r = R;
//if (!a.multiply(c).remainder(sqra.add(sqrb)).equals(ZERO())) l = l.add(ONE());
if (!red.equals(ZERO())) {
if (ac2.negate().compareTo(ZERO()) > 0) l = l.add(ONE());
}
while (l.compareTo(r) <= 0) {
x = (l.add(r)).divide(TWO());
dis = sqra.add(sqrb).multiply(sqr(x));
dis = dis.add(x.multiply(ac2));
dis = dis.add(sqrc);
if (dis.compareTo(sqrRb) > 0) r = x.subtract(ONE());
else l = x.add(ONE());
}
RR[0] = r;
}
BigInteger [] dd = new BigInteger[1];
BigInteger [] xx = new BigInteger[1], yy = new BigInteger[1];
BigInteger [] ll = new BigInteger[1], rr = new BigInteger[1];
BigInteger a,b,c;
BigInteger Cal()
{
if (sqrc.compareTo(sqrR.multiply(sqra.add(sqrb))) > 0) return ZERO();
if (a.equals(ZERO())) {
if (c.remainder(b).compareTo(ZERO()) != 0) return ZERO();
else {
BigInteger l = ZERO(),r = R;
BigInteger y = c.divide(b);
BigInteger sqry = sqr(y);
while (l.compareTo(r) <= 0) {
BigInteger x = (l.add(r)).divide(TWO());
if (sqr(x).add(sqry).compareTo(sqrR) <= 0) l = x.add(ONE());
else r = x.subtract(ONE());
}
return r.multiply(TWO()).add(ONE());
}
} else if (b.equals(ZERO())) {
if (!c.remainder(a).equals(ZERO())) return ZERO();
else {
BigInteger l = ZERO(),r = R;
BigInteger x = c.divide(a);
BigInteger sqrx = sqr(x);
while (l.compareTo(r) <= 0) {
BigInteger y = (l.add(r)).divide(TWO());
if (sqrx.add(sqr(y)).compareTo(sqrR) <= 0) l = y.add(ONE());
else r = y.subtract(ONE());
}
return r.multiply(TWO()).add(ONE());
}
}
BigInteger ans = ZERO();
gcd(a,b,dd,xx,yy);
BigInteger d = dd[0], x = xx[0];
if (c.remainder(d).compareTo(ZERO()) != 0) return ZERO();
x = x.multiply(c.divide(d)).negate();
GetBound(ll,rr);
BigInteger l = ll[0], r = rr[0];
if (l.compareTo(r) > 0) return ZERO();
BigInteger k = ZERO();
d = b.divide(d);
if (d.compareTo(ZERO()) < 0) d = d.negate();
if (x.compareTo(l) > 0) {
k = (l.subtract(x)).divide(d);
x = x.add(k.multiply(d));
}
if (x.compareTo(l) < 0) {
k = (l.subtract(x)).divide(d);
x = x.add(k.multiply(d));
while (x.compareTo(l) < 0) x = x.add(d);
}
if (r.compareTo(x) >= 0) k = ((r.subtract(x)).divide(d)).add(ONE());
else k = ZERO();
ans = k;
return ans;
}
void solve()
{
a = valueOf(y11-y22);
b = valueOf(x22-x11);
c = valueOf(x11*y22-x22*y11);
sqrR = sqr(R); sqra = sqr(a); sqrb = sqr(b);
sqrRb = sqrR.multiply(sqrb);
BigInteger sum = ZERO();
c = c.add(S);
sqrc = sqr(c);
m = a.multiply(c).divide(sqra.add(sqrb)).negate();
red = a.multiply(c).remainder(sqra.add(sqrb));
sum = sum.add(Cal());
//long std_ans = BruteForce();
c = c.subtract(S.multiply(TWO()));
sqrc = sqr(c);
m = a.multiply(c).divide(sqra.add(sqrb)).negate();
sum = sum.add(Cal());
/*std_ans += BruteForce();
if (sum.longValue() != std_ans) {
System.out.println("Wrong answer");
System.out.println(S);
System.out.println(x00 + " " + y00 + " " + R);
System.out.println( (x11 + x00) + " " + (y11+y00));
System.out.println((x22+x00) + " " + (y22+y00));
}
out.println(std_ans);*/
out.println(sum);
out.flush();
}
Solver() throws IOException
{
cin.nextToken();
int T; T = (int)cin.nval;
for(int i = 0; i < T; ++i) {
input();
solve();
}
}
}
}
/*
123
100000000
0 0 100000000
23 45
55 100
100000000
0 0 100000000
23 45
2 100
3
0 0 5
0 2
-2 1
3
0 0 5
3 4
1 3
3
0 0 5
6 4
8 3
3
0 0 5
6 4
4 3
609
0 0 253
-217 195
-216 0
180
0 0 80
-51 78
-51 0
255
0 0 29
29 27
-27 0
609
0 0 253
-217 195
-216 0
*/