把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

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

点此看题面

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

前言

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

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

容斥

显然可以考虑容斥吧。

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

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

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

考虑我们枚举左右两点横纵坐标差值\(i,j\),令\(g=gcd(i,j)\),则中间的点必然只有\(g-1\)种选择(因为必须要取格点),而选出这样一对点的方案数又有\((n-i)\times(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\n",ans),0;
}
posted @ 2020-06-02 16:45  TheLostWeak  阅读(113)  评论(0编辑  收藏  举报