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

[bzoj3505][數論]數三角形

Description

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

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

Input

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

Output

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

Sample Input

2 2

Sample Output

76

HINT

資料範圍

1<=m,n<=1000

題解

有點妙啊… 先n++,m++ 想到了尋找三點共線的方案但是隻會n4n^4… 首先橫豎兩種方案可以很容易去掉 只考慮斜著的線段 列舉以這條邊為對角線的矩陣邊長i,j 那麼這條線段內會經過gc

d(i,j)1gcd(i,j)-1個整點 那麼這條邊,實際上是可以平移的 一共可以平移(ni)(mj)(n-i)*(m-j)次 固定了兩端的點 在中間選點共有gcd(i,j)1gcd(i,j)-1種方案 一條線段的貢獻就是 2(gcd(i,j)1)(ni)(mj)2*(gcd(i,j)-1)*(n-i)*(m-j)

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include<ctime>
#define LL long long
#define mp(x,y) make_pair(x,y)
using namespace std;
inline int read()
{
	int f=1,x=0;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}
inline void write(int x)
{
	if(x<0)putchar('-'),x=-x;
	if(x>9)write(x/10);
	putchar(x%10+'0');
}
inline void print(int x){write(x);printf(" ");}
LL C(LL n)
{
	if(n<3)return 0;
	return n*(n-1)*(n-2)/6;
}
LL gcd(LL a,LL b){return a==0?b:gcd(b%a,a);}
LL n,m;
int main()
{
	n=read();m=read();n++;m++;
	LL ans=C(n*m)-n*C(m)-m*C(n);
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			ans-=2*(gcd(i,j)-1)*(n-i)*(m-j);
	printf("%lld\n",ans);
	return 0;
}