[CQOI2014]数三角形
Posted ppxppx
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[CQOI2014]数三角形相关的知识,希望对你有一定的参考价值。
题意:给定一个nxm的网格,计算三点都在格点上的三角形共有多少个?注意三角形的三点不能共线.
分析:nxm的网格有tot=(n+1)*(m+1)个格点,暴力算出所有方案数(C_{tot}^3),然后减去平行于x轴和y轴的共线三角形((n+1)*C_{m+1}^3)和((m+1)*C_{n+1}^3),最后减去倾斜直线上的共线三角形.
这个比较麻烦,我先直接给出式子,然后再来具体分析,因为懒得画图(其实是不会),所以就只能耐心地口胡(2*(gcd(i,j)-1)*(n+1-i)*(m+1-j))
乘2:矩形具有对称性,所以倾斜直线也是对称的(就是说把倾斜直线看作一种是自左上往右下,另一种是自右上往左下,这两种情况是相同的,所以我们下面可以只讨论一种情况)
乘gcd(i,j)-1:首先要知道一个结论,对于点(a,b)和(x,y)连成的线段而言(其中a>x,b>y),在它们中间有gcd(a-x,b-y)-1个整点(自己画几个图就能发现这个规律了),然后我们不妨以左上角(0,0)点为枚举矩形的左上角顶点,所以我们只需要枚举右下角顶点(i,j)就可以了.根据结论这两个点连成的线段中间有gcd(i-0,j-0)-1个格点.
对于(n*m)的网格而言,像上述那样枚举矩形的话,一共有(n+1-i)*(m+1-j)个矩形(这里不明白也画几个图吧)
int gcd(int x,int y){
if(y==0)return x;
return gcd(y,x%y);
}
int main(){
int m=read(),n=read();
m++;n++;//为了方便,这里直接都+1了
int tot=m*n;
long long ans=1LL*tot*(tot-1)*(tot-2)/6-1LL*m*n*(n-1)*(n-2)/6-1LL*n*m*(m-1)*(m-2)/6;
for(int i=1;i<n;i++)
for(int j=1;j<m;j++)
ans-=1LL*2*(gcd(i,j)-1)*1LL*(n-i)*(m-j);
printf("%lld
",ans);
return 0;
}
以上是关于[CQOI2014]数三角形的主要内容,如果未能解决你的问题,请参考以下文章