数三角形(二)

题目描述

给定一个由 𝑛×𝑚n×m个方格组成的网格图,若从这个网格图中任意挑选三个格点(格点就是网格图中某个方格的某个顶点),请问有多少种组合可以让这个三个点成为三角形的顶点?

输入格式

两个整数:𝑛n 和 𝑚m。

输出格式

单个整数:表示三角形的数量。

数据范围
  • 对 30%30% 的数据,1≤𝑛,𝑚≤101≤n,m≤10;
  • 对 60%60% 的数据,1≤𝑛,𝑚≤5001≤n,m≤500;
  • 对 100%100% 的数据,1≤𝑛,𝑚≤30001≤n,m≤3000。
样例数据

输入1:

1 1

输出1:

4

输入2:

2 2

输出2:

76

算法思路
1、一个直观的思路是筛除法,即:答案=总数-三点共线的种数
总数易求得,为组合数C((n+1)*(m+1),3),考虑到n、m数值范围,考虑用long long
2、三点共线的情况有:
(1)网格顶点同行,每行有m+1个顶点,共n+1行,共有:C(m+1,3) * (n+1)
(2)网格顶点同列,每列有n+1个顶点,共m+1列,共有:C(n+1,3) * (m+1)
(3)网格顶点同在斜线上,分斜向上和斜向下,显然者方案数是一样的,下面考虑斜向下情况:

例如:n=5 m=7
(1)以行数为X、列数为Y的二维平面表示方格网络n*m,左上方格顶点为原点(0,0)。
(2)尝试从某网格顶点A朝斜向下方向的点B连斜线,不难总结出斜线结论:方格顶点A、B斜连线上有gcd(BC,AC)+1个点(BC、AC为A、B在X、Y轴的差,1≤AC≤m,1≤BC≤n)。
3、故而,对于斜向下的斜线,我们只需枚举两个方格顶点对(i,j):两者满足在X轴、Y轴上分别相差i、j,可取定两端顶点,再在其间取一点构成三点共线,共有方案数为gcd(i,j)-1。易知,每个(i,j)点对都有(n-i+1) * (m-j+1)种,枚举(i,j)复杂度为O(𝑛2n2),gcd复杂度为O(n)。
4、如此,时间复杂度为O(𝑛2n2lgn),考虑到n的规模,可AC。

#include<bits/stdc++.h>
using namespace std;
/*结论:对于二维n*m方格网,若AC//Y轴,BC//X轴,
则斜线AB上有gcd(BC,AC)+1个方格顶点(1<=AC<=m 1<=BC<=n)。
对于斜线:可枚举X轴差为i、Y轴差j的两点,
对该点对(i,j)取定两端点,则三点共线方案有gcd(i,j)-1,
整个方格网有这样的点对(i,j)数为(n-i+1)*(m-j+1),
故总方案数=sum{(n-i+1)*(m-j+1)*(gcd(i,j)-1)} (1<=i<=n, 1<=j<=m)
枚举时间复杂度为O(n^2),gcd(i,j)时间复杂度为lgn,总时间复杂度:O(n*nlgn)*/
const int N=3e3+10;
typedef long long ll;
ll n,m,ans,sum;
ll calc(ll x){//计算组合数C(x,3)
	return x*(x-1)*(x-2)/6;
}int gcd(int x,int y){//最大公约数
	if(y==0) return x;
	return gcd(y,x%y);
}signed main(){
	cin>>n>>m;//n行m列
	ans=calc((n+1)*(m+1));//最多可构成三角形数(去掉任意三点共线的情况)
	ans-=(calc(n+1)*(m+1)+calc(m+1)*(n+1));//同列、同行三点共线种数
	for(int i=1;i<=n;i++)//枚举斜向下的斜线点对:(i,j)	
		for(int j=1;j<=m;j++)
			sum+=(n-i+1)*(m-j+1)*(gcd(i,j)-1);
	ans-=sum*2;cout<<ans;
}

 

  • 8
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值