1. 程式人生 > >bzoj3505: [Cqoi2014]數三角形 [數論][gcd]

bzoj3505: [Cqoi2014]數三角形 [數論][gcd]

我們 font for res 枚舉 cout blog esc ace

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]