【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;
}
待到再迷茫时回头望,所有脚印会发出光芒