trokuti(32M1S)
拿到这道题,第一个想到的就是NlogN。。。。
首先倾斜角相同的线可以看作一条,然后存下倾斜角为这个的直线条数。
对于每一类直线,我们假设它以后的直线的斜率都不相同,假设它后面有K条直线,这样它和它后面能组成的三角形就是(K*(K-1))/2;
而它后面是有倾斜角相同的直线的,对于它后面每一类直线假设有N条,那么对于这类直线我们多选的就是(n)*(n-1)/2条;
这样我们可以得到这个直线的三角形数为 (K*(K-1))减去后面所有类直线多选的和。
后面多选的和可以预先处理出来,这样算法的复杂度就变成了(nlogn+n);
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#define N 300000+10
#define mod 1000000007
#define eps 1e-8
#define ll long long
#include<cmath>
using namespace std;
int n;
struct line
{
int a,b,c;
ll ge;
double angle;
void getangle(int a,int b)
{
double aa=double(a);
double bb=double(b);
angle=atan2(bb,-aa);
}
void read()
{
scanf("%d%d%d",&a,&b,&c);
getangle(a,b);
}
}seg[N],map[N];
ll sum[N],duo[N];
ll ans;
bool cmp(line a,line b)
{
return (a.angle-b.angle)<-eps;
}
bool pd(int now,int a)
{
return (fabs(seg[now].angle-seg[a].angle))<eps;
}
int main()
{
freopen("trokuti.in","r",stdin);
freopen("trokuti.out","w",stdout);
scanf("%d",&n);
for (int i=1;i<=n;i++)
seg[i].read();
sort(seg+1,seg+1+n,cmp);
int now=1;
int tot=0;
for (int i=2;i<=n+1;i++)
{
if (!pd(now,i))
{
map[++tot]=seg[now];
map[tot].ge=i-now;
now=i;
}
}//去重。
for (int i=tot;i>=1;i--)
{
sum[i]=sum[i+1]+map[i+1].ge;//求后面有多少个。
}
for (int i=tot;i>=1;i--)
{
duo[i]=(duo[i+1]+((ll)(map[i+1].ge)*(ll)(map[i+1].ge-1)));//求后面多算的。
}
for (int i=1;i<=tot;i++)
{
ll kk=(ll) (((ll)(sum[i]*(sum[i]-1)*map[i].ge))-(ll)(map[i].ge*duo[i]));
kk=kk/2;
ans+=kk;
ans%=mod;
//注意因为有除法所以不能MOD我们只能开LL;
}
printf("%I64d",ans);
return 0;
}