码迷,mamicode.com
首页 > 其他好文 > 详细

bzoj3505: [Cqoi2014]数三角形 [数论][gcd]

时间:2017-08-04 13:54:02      阅读:161      评论:0      收藏:0      [点我收藏+]

标签:int   固定   线段   i++   范围   另一个   三角形   输入   div   

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]

标签:int   固定   线段   i++   范围   另一个   三角形   输入   div   

原文地址:http://www.cnblogs.com/ZYBGMZL/p/7284430.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!