1. 程式人生 > >[BZOJ][CQOI2014]數三角形

[BZOJ][CQOI2014]數三角形

strong esp 計算 包含 成了 spa str algorithm cqoi2014

Description

給定一個nxm的網格,請計算三點都在格點上的三角形共有多少個。下圖為4x4的網格上的一個三角形。

註意三角形的三點不能共線。

Input

輸入一行,包含兩個空格分隔的正整數m和n。

Output

輸出一個正整數,為所求三角形數量。

Sample Input

2 2

Sample Output

76

數據範圍
1<=m,n<=1000

因為就在做這道題之前看的一道題……下意識以為只有直線和對角線的情況,然後搞成O(n)算法似乎自己比其他寫題解的神犇厲害??事實上我錯了,,,orz(霧(跪地(無奈(orz(%%%(逃

首先,顯然的,不考慮三點共線共有C(n*m,3)種方法,所以問題轉化為三點共線有幾種情況?

在(x1,y1) (x2,y2)兩點構成的線段(不含端點)上有gcd(x1-x2,y1-y2)-1個整點。

所以我們可以在logn的時間求出一條線段中的整點個數,但枚舉兩個點顯然要超時,所以我們只枚舉一個點的坐標,它與(0,0)顯然構成了唯一的一條線段,然後我們發現這條線段其實可以移動,所以就將一條線段的解*(n-x)*(m-y)

相減就得到答案啦~~

#include<cstdio>
#include<algorithm>
#define ll long long
using namespace std;
ll n,m;
ll gcd(ll a,ll b){
    
return b?gcd(b,a%b):a; } int main(){ scanf("%lld%lld",&n,&m); n++;m++; ll ans=(n*m)*(n*m-1)*(n*m-2)/6; for(int i=0;i<n;i++) for(int j=0;j<m;j++){ ll c; if(!i)c=j-1; if(!j)c=i-1; if(i&&j)c=gcd(i,j)-1; if(c<0)c=0;
if(i&&j)ans-=c*(n-i)*(m-j)*2;else ans-=c*(n-i)*(m-j); } printf("%lld",ans); }

[BZOJ][CQOI2014]數三角形