题意就不说了。。
第一次遇见这种题目,没学过直线方程,所以只打了个暴力,以为大家都做不出来的。。结果发现好像很多人都切了。。然后有点慌,最后半个小时想出了正解但是没有打完,手忙脚乱结果把拍给交上去了。。以后对于这种题目不能怕,要认真分析,如果真的不会在放弃。。
题解:我们对于直接统计答案发现有一定难度,那么正难则反。把不合法的去掉,用组合数。但是先要把直线按照比例从小到大排。
type node=record
x,y:int64;
end;
const mo=1000000007;
var
i,j,k,p,n,m,l,x,y,z:longint;
fac,inv:Array[0..1000000]of int64;
a:array[0..1000000]of node;
ans,d:int64;
function pow(a,b:int64):int64;
var
base,r:int64;
begin
base:=a;
r:=1;
while b<>0 do
begin
if b and 1<>0 then r:=r*Base mod mo;
base:=base*Base mod mo;
b:=b div 2;
end;
exit(r);
end;
procedure qsort(l,r:longint);
var
i,j:longint;
t,m,m1:int64;
begin
i:=l;
j:=r;
m:=a[(l+r)div 2].x;
m1:=a[(l+r)div 2].y;
repeat
while(a[i].x<m)or((a[i].x=m)and(a[i].y<m1))do inc(i);
while(a[j].x>m)or((a[j].x=m)and(a[j].y>m1))do dec(j);
if i<=j then
begin
a[0]:=a[i];
a[i]:=a[j];
a[j]:=a[0];
inc(i);
dec(j);
end;
until i>j;
if l<j then qsort(l,j);
if i<r then qsort(i,r);
end;
function gcd(a,b:longint):longint;
begin
if a mod b=0 then exit(b)
else exit(gcd(b,a mod b));
end;
begin
assign(input,'trokuti.in');
assign(output,'trokuti.out');
reset(input);
rewrite(output);
readln(n);
for i:=1 to n do
begin
readln(x,y,z);
if y=0 then
begin
a[i].x:=0;
a[i].y:=0;
continue;
end;
d:=gcd(x,y);
a[i].x:=x div d;
a[i].y:=y div d;
end;
qsort(1,n);
inv[0]:=1;
fac[0]:=1;
for i:=1 to n do fac[i]:=fac[i-1]*i mod mo;
for i:=1 to n do inv[i]:=pow(fac[i],mo-2);
ans:=fac[n]*inv[3]mod mo*inv[n-3]mod mo;
i:=1;
while i<=n do
begin
j:=i;
while(a[j].x=a[j+1].x)and(a[j].y=a[j+1].y)and(j<n)do inc(j);
l:=j-i+1;
if l>1 then
ans:=(ans-fac[l]*inv[2]mod mo*inv[l-2]mod mo*(n-l)mod mo+mo)mod mo;
if l>2 then
ans:=(ans-fac[l]*inv[3]mod mo*inv[l-3]mod mo+mo)mod mo;
i:=j+1;
end;
writeln(ans);
end.