3505: [Cqoi2014]数三角形
Time Limits:
1000 ms Memory Limits: 524288 KB Detailed Limits
Description
![](https://img-blog.csdnimg.cn/2022010711085958075.png)
Input
输入一行,包含两个空格分隔的正整数m和n。
Output
输出一个正整数,为所求三角形数量。
Sample Input
输入1:
1 1
输入2:
2 2
Sample Output
输出1:
4
输出2:
76
Data Constraint
对于30%的数据 1<=m,n<=10
对于100%的数据 1<=m,n<=1000
对于100%的数据 1<=m,n<=1000
题解:
数论
首先,我们可以将问题转化一下, 可以形成的三角形的个数=任选三个点的个数-三点共线个数
设总点数为k,则k=(n+1)*(m+1)
任选三个点的个数很简单:(k*(k-1)*(k-2))/6
至于三点共线个数,我们可以发现枚举每个点(i,j),则 (i,j) 和 (1,1) 再和 其他的一个点 能共线的个数为Gcd(i,j)-1,还有,因为我们枚举的点为(i,j),我们可以把(1,1)和(i,j)看为一个矩形,那么明显是可以在大的矩形中移动的。也就是我们算的线为(1,1)到(i,j)的线,但是其平行的线我们还要再算的,所以用 每个点的个数乘上(n-i+1)*(m-j+1)。然后我们把所有的点都计算一遍,然后把 和 乘2(因为我们刚才考虑的为从左下角往右上角偏的,不一定是平行,也就是和这个箭头差不多的方向↗️。我们还要考虑这种样子的↖️,显然两种的个数相等,所以要乘2。)最后,我们发现左右的线↔️和上下的线↕️没有减去,所以要单独减。
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define LL long long 4 LL Gcd(int aa,int bb){if(bb==0)return aa;else return Gcd(bb,aa%bb);} 5 int main() 6 { 7 LL n,m,k,k1,ans,i,j,tot=0; 8 scanf("%lld %lld",&n,&m); 9 k=(n+1)*(m+1); 10 ans=k*(k-1)*(k-2)/6; 11 for(i=1;i<=n;i++) 12 { 13 for(j=1;j<=m;j++) 14 { 15 k=Gcd(i,j); 16 if(k>=2)tot+=(k-1)*(n-i+1)*(m-j+1); 17 } 18 } 19 n++;m++; 20 k=m*(m-1)*(m-2)/6; 21 k1=n*(n-1)*(n-2)/6; 22 ans-=(n*k+m*k1); 23 printf("%lld",ans-tot*2); 24 fclose(stdin); 25 fclose(stdout); 26 return 0; 27 }