NOIP11.15模拟 T1 SJR的直线

题意就不说了。。
第一次遇见这种题目,没学过直线方程,所以只打了个暴力,以为大家都做不出来的。。结果发现好像很多人都切了。。然后有点慌,最后半个小时想出了正解但是没有打完,手忙脚乱结果把拍给交上去了。。以后对于这种题目不能怕,要认真分析,如果真的不会在放弃。。
题解:我们对于直接统计答案发现有一定难度,那么正难则反。把不合法的去掉,用组合数。但是先要把直线按照比例从小到大排。

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.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值