三角形
【 问题描述 】
平面上有N条直线,用方程A i x + B i y +C i=0表示。这些直线没有三线共点的。现在要你计算出用这些直线可以构造出多少三角形?
【 输入格式 】
第1行:一个整数N(1 ≤ N≤ 300000)。
下面N行:每行3个整数:Ai, Bi 和Ci,表示对应直线方程的系数。不超过10^9.
【 输出格式 】
一行,一个整数。
input 1
6
0 1 0
-5 3 0
-5 -2 25
0 1 -3
0 1 -2
-4 -5 29
output 1
10
input 2
5
-5 3 0
-5 -3 -30
0 1 0
3 7 35
1 -2 -1
output 2
10
【 数据规模与约定 】
对于40%的数据,N ≤1000;
对于100%的数据,N≤300000。
/* 又是一道让我明白数学重要性的题目,最近做数学题快做哭了。我拿到题目,第一时间想到的是三个点确定一个三角形,然后用了40%的做法,无情地爆零了,至今还不知道为什么。 AC做法是听学哥讲的: 一个三角形由三条不同斜率的边组成(好有道理的样子),这个题要求出n条直线的斜率,将它们排序,如果斜率都不相同,那么结果就是C(n,3),但是有相同的情况,既有多条边平行的情况,由于这是三角形,所以平行的情况只有两种,一是两条边平行,而是三条边都平行,怎么处理这种情况呢?记录每组斜率相同的边的个数len,如果个数len[i]>=2,说明它能组成以上的第一种情况,就要在答案中减去(n-len[i])*C(len[i],2) ;如果len[i]>=3,说明它能组成以上的第二种情况,就要在答案中减去C(len[i],3)。得出的结果即为最终答案。 */ #include<cstdio> #include<iostream> #include<algorithm> #define ll long long #define N 300010 using namespace std; double k[N],a[N],b[N],c[N]; ll n,cnt,len[N]; ll C(ll x,ll num) { if(num==2)return x*(x-1)/2; if(num==3)return x*(x-1)*(x-2)/6; } int main() { //freopen("jh.in","r",stdin); freopen("trokuti.in","r",stdin); freopen("trokuti.out","w",stdout); cin>>n; for(ll i=1;i<=n;i++) { scanf("%lf%lf%lf",&a[i],&b[i],&c[i]); k[i]=-a[i]/b[i]; } sort(k+1,k+n+1); len[++cnt]=1;double now=k[1]; for(ll i=2;i<=n;i++) if(k[i]!=now) { len[++cnt]=1; now=k[i]; } else len[cnt]++; ll ans=C(n,3); for(ll i=1;i<=cnt;i++) { if(len[i]>=2)ans-=C(len[i],2)*(n-len[i]); if(len[i]>=3)ans-=C(len[i],3); } cout<<ans; return 0; }