【BZOJ3505】[CQOI2014] 数三角形(容斥一眼题)

点此看题面

大致题意: 问一张(n imes m)的网格图上格点三角形数目。

前言

看到网格图就要想到分治。by 【BZOJ4456】[ZJOI2016] 旅行者

做了几乎一天的类欧几里得题目,现在找道水题放松一下心情。

容斥

显然可以考虑容斥吧。

选出三个点总方案数为(C_{n imes m}^3),然后减去三点共线的情况数即为答案。

而三点共线可以分成在同一行上,同一列上,或是一条斜线上。

在同一行上的方案数显然是(n imes C_m^3),同一列上显然是(m imes C_n^3),而斜线要稍微有技巧一点。

考虑我们枚举左右两点横纵坐标差值(i,j),令(g=gcd(i,j)),则中间的点必然只有(g-1)种选择(因为必须要取格点),而选出这样一对点的方案数又有((n-i) imes(m-j))种。

不过由于斜线既可以斜着向上,也可以斜着向下,因此方案数还要乘(2)

代码

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 1000
#define LL long long
#define C(x) (1LL*(x)*((x)-1)*((x)-2)/6)//求C(x,3)
using namespace std;
int n,m;I int gcd(CI x,CI y) {return y?gcd(y,x%y):x;}//求gcd
int main()
{
	scanf("%d%d",&n,&m),++n,++m;LL ans=C(n*m)-1LL*n*C(m)-1LL*m*C(n);//容斥
	RI i,j;for(i=1;i<=n;++i) for(j=1;j<=m;++j) ans-=2LL*(gcd(i,j)-1)*(n-i)*(m-j);//减去斜线情况
	return printf("%lld
",ans),0;
}
原文地址:https://www.cnblogs.com/chenxiaoran666/p/BZOJ3505.html