数三角形

数三角形

题解

xx(省略)数学题!!!考场上怎么打错了!!!

组合+数论+容斥

显而易见,三角形的个数=所有三个点的组合-水平线的三点组合-铅垂线的三点组合-斜线的三点组合

我们先把n与m分别加1,求出横线数与竖线数。

所有三个点的组合:C_{3}^{nm}

水平线的三点组合:nC_{3}^{nm}

铅垂线的三点组合:mC_{3}^{nm}

重点是下面的,十分重要。

子命题:\left ( a,b \right )\left ( x,y \right )两点间的整点个数为\left ( a-x,b-y \right )-1

接下来是证明,因为是整点,所以他们两点构成的大三角形一定可以被分解为若干个小三角形(最少一个),且其边为整数。

最小三角形两边应为\frac{a-x}{\left ( a-x,b-y \right )}\frac{b-y}{\left ( a-x,b-y \right )}

所以除两端点外的整点个数为\left ( a-x,b-y \right )-1

为了没有重复的,我们可以用两端点枚举中间的点。

这样时间复杂度为O\left ( n^{2}m^{2} \right )。这样还是要超时。

因为矩阵的对称性,我们只需枚举k> 0的情况

我们可以考虑将左下的那个移动到原点,先看这种情况的数量,再枚举其可能的平移操作。

设这个点的的坐标为\left ( i,j \right ),则这个点可以向上平移n-i,向右平移m-j,所以总共可以平移的状态为(n-i)(m-j)种。

每种的点数为\left ( i,j \right )(n-i)(m-j),所以,

斜线的三点组合:\sum_{i=1}^{n}\sum_{j=1}^{m}12(\left ( i,j \right )-1)(n-i)(m-j)

别忘了,最后的三角形数还应除A_{3}^{3}即6,因为有重复的三角形。

源码

#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<set>
using namespace std;
typedef long long LL;
const LL INF=0x7f7f7f7f7f7f;
LL n,m,ans;
#define gc() getchar()
template<typename _T>
inline void read(_T &x)
{
    _T f=1;x=0;char s=gc();
    while(s>'9'||s<'0'){if(s=='-')f=-1;s=gc();}
    while(s>='0'&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=gc();}
    x*=f;
}
LL gcd(LL a,LL b)
{
	if(!b)
		return a;
	return gcd(b,a%b);
} 
int main()
{
	read(n);read(m);
	LL tmp=(n+1LL)*(m+1LL);
	ans=tmp*(tmp-1LL)*(tmp-2LL)/6LL;
	ans-=(n+1LL)*m*(m-1LL)*(m+1LL)/6LL;
	ans-=(m+1LL)*n*(n-1LL)*(n+1LL)/6LL;
	for(int i=0;i<=n;i++)
		for(int j=0;j<=m;j++)
		{
			LL tmp=(gcd(i+1,j+1)-1)*(n-i)*(m-j)*2LL;
			ans-=tmp; 
		}
	printf("%lld",ans);
    return 0;
}

谢谢!!!

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值