bzoj3505: [Cqoi2014]数三角形 [数论][gcd]
Posted ZYBGMZL
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj3505: [Cqoi2014]数三角形 [数论][gcd]相关的知识,希望对你有一定的参考价值。
Description
给定一个nxm的网格,请计算三点都在格点上的三角形共有多少个。下图为4x4的网格上的一个三角形。
注意三角形的三点不能共线。
Input
输入一行,包含两个空格分隔的正整数m和n。
Output
输出一个正整数,为所求三角形数量。
Sample Input
2 2
Sample Output
76
数据范围
1<=m,n<=1000
太伤心了。。不能abs(int)???
首先格点个数是(n+1)*(m+1)的,所以我们先把n和m都+1。 先选出三个不同点,方案数是C(n*m,3)。 接下来扣掉三点共线的情况。 枚举两个点,计算以它们为端点的线段上的整点个数。 不难发现是gcd(x1-x2,y1-y2)-1。 线段是可以平移的,那么我们把其中一个点固定在(0,0),只枚举另一个点的坐标,然后乘上方案数就行了。 时间复杂度O(nm)
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 using namespace std; 5 #define dbg(x) cout<<#x<<" = "<<x<<endl 6 7 typedef long long ll; 8 9 const int maxn=1005; 10 11 int n,m,f[maxn][maxn],ens; 12 ll ans; 13 14 ll C(int a,int b){ 15 ll res=1; 16 for(int i=a;i>a-b;i--) res*=i; 17 for(int i=b;i>1;i--) res/=i; 18 return res; 19 } 20 21 int gcd(int a,int b){ 22 if(f[a][b]) return f[a][b]; 23 return b?(f[a][b]=gcd(b,a%b)):a; 24 } 25 26 int main(){ 27 scanf("%d%d",&n,&m); 28 n++; m++; 29 ans=C(n*m,3); 30 for(int i=-n+1;i<=n-1;i++) 31 for(int j=0;j<=m-1;j++){ 32 //避免重复计算 33 if(!j&&i<=0) continue; 34 ens=gcd(i<0?-i:i,j)-1; 35 // dbg(abs(i)); dbg(j); dbg(ens); 36 ans-=1ll*ens*(n-(i<0?-i:i))*(m-j); 37 } 38 printf("%lld\\n",ans); 39 return 0; 40 }
以上是关于bzoj3505: [Cqoi2014]数三角形 [数论][gcd]的主要内容,如果未能解决你的问题,请参考以下文章
BZOJ-3505: [Cqoi2014]数三角形 (容斥原理+排列组合)
bzoj 3505 [Cqoi2014]数三角形——排列组合