3505: [Cqoi2014]数三角形
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1754 Solved: 1082
[Submit][Status][Discuss]
Description
给定一个nxm的网格,请计算三点都在格点上的三角形共有多少个。下图为4x4的网格上的一个三角形。
注意三角形的三点不能共线。
Input
输入一行,包含两个空格分隔的正整数m和n。
Output
输出一个正整数,为所求三角形数量。
Sample Input
2 2
Sample Output
76
数据范围
1<=m,n<=1000
数据范围
1<=m,n<=1000
HINT
Source
今天下午校内自测爆零了……哇的一声哭了出来QAQ 第一题黑心的秤砣竟然给了道省选题……
苦逼的laj其实20分钟就想到正解了哇,就是要用容斥原理先算出总共的个数包括合法的和不合法的,然后减掉三个点分别在同一行,同一列,还有同一条斜线上的不合法情况……然鹅laj花了2h都没写好统计在同一条斜线上的不合法情况的种类数QAQ,感觉还是陷到瓶颈里了QAQ一直都是想着那条斜线的斜率是小于0的情况,秤砣的算法在写什么鬼东西啊……还是肫的话点醒了laj,为了不与之前斜率一样的情况重复统计,这里首先固定两个点(1,1)和(x,y)然后通过gcd(x-1,y-1)+1算出这条斜线上的整点的个数,减掉固定的两个端点,剩下的就是自由的可行的点,每个点都分别代表着一种不同的情况,因为已经固定的两个点是这三个点之间距离最大的两个点,这个距离一定大于之前算的斜率相同的距离最大的两个点的距离,所以易证不会和之前算的情况重合,对于每个(1,1)到(x,y)的线段,在这个矩阵里总共有(n-x+1)*(m-y+1)条,最后统计一下即可算出答案(因为矩阵的对称性,这只是算出了线段的斜率大于0 的情况,还有对称的斜率小于0的情况,所以斜线上减掉的不合法情况数要乘二)
原来laj离真相就差那么一小步…… _(:зゝ∠)_
1 #include "bits/stdc++.h" 2 using namespace std; 3 typedef long long LL; 4 const int MAX=1005; 5 LL n,m,ans; 6 LL gcd(LL x,LL y){return (y==0?x:gcd(y,x%y));} 7 LL c(LL x,LL y){ 8 LL i,j,an=1; 9 for (i=1;i<=y;i++) an*=(x-i+1); 10 for (i=2;i<=y;i++) an/=i; 11 return an; 12 } 13 int main(){ 14 freopen ("nmtg.in","r",stdin); 15 freopen ("nmtg.out","w",stdout); 16 LL i,j,k,zt=0; 17 scanf("%lld%lld",&n,&m);n++,m++; 18 ans=c(n*m,3)-(n*c(m,3)+m*c(n,3)); 19 for (i=2;i<=n;i++){ 20 for (j=2;j<=m;j++){ 21 k=gcd(i-1,j-1); k++; 22 if (k<3) continue; 23 ans-=2*(k-2)*(n-i+1)*(m-j+1); 24 } 25 } 26 printf("%lld",ans); 27 return 0; 28 }