qzezoj 1592 三角形计数
题面传送门
题目告诉我们,没有三点共线,所以我们可以容斥。
两条线,\(x,y\)相等,即平行。那么我们可以用总可能数-\(2\)条直线平行-\(3\)条直线平行。
用\(hash\)来判断平行线。
代码实现:
#include<cstdio>
#include<cstring>
#include<cmath>
#define mod 600017
using namespace std;
long long n,ans,pus,flag[300039],tot[300039],f1[300039],f2[300039],z[300039],h[600039],g[300039],head,sx[300039],sy[300039],sz[300039];
inline void add(long long x,long long y) {
long long now=(long long)abs(x*y)%mod,ss=h[now];
while(ss) {if(f1[ss]==x&&f2[ss]==y) break;ss=z[ss];}
if(!ss) f1[++head]=x,f2[head]=y,z[head]=h[now],h[now]=head,g[head]=1;
else g[ss]++;
}
inline long long _hash(long long x,long long y) {
long long now=(long long)abs(x*y)%mod,ss=h[now];
while(ss) {if(f1[ss]==x&&f2[ss]==y) break;ss=z[ss];}
if(!flag[ss]) {flag[ss]=1;return g[ss];}
return 0;
}
inline void read(long long &x) {
char s=getchar();int f=1;x=0;
while(s<'0'||s>'9') {if(s=='-') f=-1;s=getchar();}
while(s>='0'&&s<='9') x=(x<<3)+(x<<1)+(s^48),s=getchar();
x*=f;
}
int main() {
register int i;
read(n);
for(i=1; i<=n; i++) read(sx[i]),read(sy[i]),read(sz[i]),add(sx[i],sy[i]);
ans=(n*(n-1)*(n-2)/6)%1000000007;
for(i=1; i<=n; i++) {
tot[i]=_hash(sx[i],sy[i]);
if(tot[i]) {
ans-=tot[i]*(tot[i]-1)*(tot[i]-2)/6%1000000007;
if(ans<0) ans+=1000000007;
ans-=tot[i]*(tot[i]-1)/2%1000000007*(n-tot[i])%1000000007;
if(ans<0) ans+=1000000007;
}
}
printf("%lld\n",ans);
}

浙公网安备 33010602011771号