bzoj3505: [Cqoi2014]數三角形 [數論][gcd]
阿新 • • 發佈:2017-08-04
我們 font for res 枚舉 cout blog esc ace
數據範圍
1<=m,n<=1000
Description
給定一個nxm的網格,請計算三點都在格點上的三角形共有多少個。下圖為4x4的網格上的一個三角形。
註意三角形的三點不能共線。
Input
輸入一行,包含兩個空格分隔的正整數m和n。
Output
輸出一個正整數,為所求三角形數量。
Sample Input
2 2Sample 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(inta,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]