洛谷 P3166 [CQOI2014]数三角形 BZOJ 3505 [Cqoi2014]数三角形 - 组合数学

洛谷 P3166 [CQOI2014]数三角形

BZOJ 3505 [Cqoi2014]数三角形

题目链接:洛谷 P3166 [CQOI2014]数三角形 BZOJ 3505 [Cqoi2014]数三角形

算法标签: 组合数学最大公约数

题目

题目描述

给定一个nxm的网格,请计算三点都在格点上的三角形共有多少个。下图为4x4的网格上的一个三角形。

注意三角形的三点不能共线。

输入格式

输入一行,包含两个空格分隔的正整数m和n。

输出格式

输出一个正整数,为所求三角形数量。

输入输出样例

输入 #1

2 2

输出 #1

76

说明/提示

数据范围

bzoj上是1<=m,n<=1000

题解:

组合数学

首先对于这道题的读入,n和m是从0开始计算的,为了方便处理,不妨将n与m都++。

我们可以先考虑去枚举每一个三角形,很显然是做不到的。

那么我们可以换一种思路,我们可以确定的是每一个三角形一定有三个点,并且这三个点不共线。

对于一定有三个点,很显然我们可以得到总答案:\(ans~=~C_{n*m}^{3}\)

那么对于三点不共线,我们现在就要考虑以下的情况:

1.三点不共横线:很显然,我们枚举每一条横边,在上边任选三个点,这样的三个点都是不合法的,又因为有n条横边,所以\(ans~-=~n \times C_{m}^{3}\)

2.三点不共竖线:同上,枚举每一条竖边,任选三点除去,所以\(ans~-=~m \times C_{n}^{3}\)

3.三点不过斜线:如何判断斜线,这就是这道题的难点所在,分析后我们可以发现一个问题,对于一个\((x \times y)\)的网格矩形,从最左上角点到最右下角点的直线会经过\(gcd(x,y)-1\)个格点(不包含起点和中点),同理从最右上角点到最左下角点也会经过\(gcd(x, y)-1\)个格点,那么我们只需要枚举所有的矩形,删去这些情况即可:\(ans~-=~(n-i)*(m-j)*(gcd(i,j)-1)*2\)

最终得到的ans就是答案。

!!!注意:这道题的数据需要开\(long long\)

AC代码

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

ll n, m, ans;

ll gcd(ll a,ll b)
{
	if (b == 0)
		return a;
	return gcd(b, a % b);
}
int main()
{
	scanf("%lld%lld", &m ,&n);
	n ++ ;
	m ++ ;
	ans = (n * m) * (n * m - 1) * (n * m - 2) / (1 * 2 * 3);
	ans -= n * m * (m - 1) * (m - 2) / (1 * 2 * 3);
	ans -= m * n * (n - 1) * (n - 2) / (1 * 2 * 3);
	for (ll i = 2; i < n; i ++ )
		for (ll j = 2; j < m; j ++ )
		{
			ans -= (n - i) * (m - j) * (gcd(i, j) - 1) * 2;
		}
	printf("%lld\n", ans);
	return 0;
}
posted @ 2019-11-12 13:34  筱柒_Littleseven  阅读(160)  评论(0编辑  收藏  举报