C2 - Power Transmission (Hard Edition)
题意就是给你n个点,保证无重点,然后问你n个点两两相连构成直线,这些直线会有多少个交点?
思路就是两条直线如果不是平行就是相交的,所有我们可以把全部直线都找出来,存到set里,然后对于一条直线在用map记录和它平行的直线的数量,那么对于这条直线产生的交点数量就是总的直线数-和它平行的直线数量了。
要唯一表示一条直线需要记录它的斜率和截距(直线方程为y=x*(y1-y2)/(x1-x2)-x1*(y1-y2)/(x1-x2)+y1,因为k=dy/dx,除法会有误差所以就没用k表示斜率,这里把等式变成(x1-x2)*y=x*(y1-y2)-x1*(y1-y2)+y1*(x1-x2),这里设y和x的系数为aa,bb,常数项为cc。然后就可以利用aa和bb表示斜率了,如果2条直线斜率相等的话,那么aa和bb的比例是相同的,因此每个直线对应的aa,bb都要化到互质,然后因为是个等式,所有这个cc也是要连带着化的,然后因为会有-y=-x,和y=x这种情况,所以要定个准,保证aa>=0。
#include<bits/stdc++.h>
using namespace std;
#define fuck(x) cout<<#x<<" "<<x<<endl;
const int inf=0x3f3f3f3f;
#define ll long long
typedef pair<int,int> pii;
map<pii,int>mp;
set<pair<pii,int> >st;
pii nod[1005];
int gcd(int x,int y)
{
return y==0?x:gcd(y,x%y);
}
int main()
{
int n;
ll ans=0,tmp=0;
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d%d",&(nod[i].first),&(nod[i].second));
for(int i=1;i<=n;i++)
for(int j=i+1;j<=n;j++)
{
int dx=nod[i].first-nod[j].first,dy=nod[i].second-nod[j].second,aa,bb,cc,igcd;
if(dx==0)
aa=0,bb=1,cc=nod[i].first;
else
aa=dx,bb=dy,cc=-dy*nod[i].first+nod[i].second*dx;
igcd=gcd(aa,bb);igcd=gcd(igcd,cc);
aa/=igcd;bb/=igcd;cc/=igcd;
if(aa<0) aa=-aa,bb=-bb,cc=-cc;
if(!st.count(make_pair(make_pair(aa,bb),cc)))
st.insert(make_pair(make_pair(aa,bb),cc)),mp[make_pair(aa,bb)]++,tmp++;
}
set<pair<pii,int> >:: iterator it;
for(it=st.begin();it!=st.end();it++)
ans+=tmp-1LL*mp[(*it).first];
printf("%lld\n",ans/2);
return 0;
}