暑训日记Day3 T2《数三角形》题解 (组合+容斥+gcd)
T2 数三角形
\(Luogu\) 双倍经验:P3166
【问题描述】
\(Y\)手上有一个\(n*m\)的网格,他想知道满足三个顶点都在格点上的三角形有多少个。
【输入格式】
输入一行,包含两个正整数\(n\)和\(m\)
【输出格式】
输出一行,包含一个正整数表示答案
【样例输入】
2 2
【样例输出】
76
【数据范围】
对于30%的数据,满足\(n,m≤10\)
对于100%的数据,满足\(n,m≤1000\)
【题解】
\(数学:组合+容斥+gcd\)
\[\sum 三角形 = \sum三个点任意组合 - \sum三个点共线组合
\]
\[\sum 三角形 = C_{(m + 1)(n + 1)}^{3} - \sum三点横向排列 - \sum三点纵向排列 - \sum三点斜向排列
\]
\[\sum 三角形 = C_{(m + 1)(n + 1)}^{3} - (m + 1)C_{n+1}^3 - (n + 1)C_{m+1}^3 - 2*\sum三点斜向排列,且斜率为正
\]
现在我们最大的问题就在于如何求出三个点斜向排列,且斜率为正的情况总数
给出一个特别的结论:
对于两个点坐标分别为\((a,b)、(c,d)\),另两点横纵坐标差为\(i = |a - c|,j = |b - d|\),由于斜率已经被我们限制死了,所以\(i = a-c,j = b-d\),这两个点连线上的格点共有 \(gcd(i,j)-1\) 个,不难知道这样的点对共有\((n−i+1)(m−j+1)\)个,三点斜向排列,且斜率为正的组合共有:
\[\sum_{i = 1}^n\sum_{j = 1}^m(n - i + 1)(m - j + 1)[gcd(i,j) - 1]
\]
上面的表达式注意要乘\(2\),这道题的最终结果即为:
\[C_{(m + 1)(n + 1)}^{3} - (m + 1)C_{n+1}^3 - (n + 1)C_{m+1}^3 -2*\sum_{i = 1}^n\sum_{j = 1}^m(n - i + 1)(m - j + 1)[gcd(i,j) - 1]
\]
算呗。反正这个数学题我当时没推出来\(www\)。这道题在洛谷上是个省选难度的,放在\(T2\)不是很能理解。
#include<bits/stdc++.h>
#define REG register
#define LL long long
using namespace std;
LL n,m,ans,nm;
int main(){
freopen("tri.in","r",stdin);
freopen("tri.out","w",stdout);
scanf("%lld %lld",&n,&m);
++n,++m; nm = n * m;
ans = nm * (nm - 1) * (nm - 2) / 6
- n * m * (m - 1) * (m - 2) / 6
- m * n * (n - 1) * (n - 2) / 6;
for(REG int i = 1;i < n;i++)
for(REG int j = 1; j < m ;j++)
ans -= (LL)2 * (LL)(__gcd(i , j) - 1)
* (LL)(n - i) * (LL)(m - j);
printf("%lld",ans);
return 0;
}
看完请留下你的痕迹\(thx\)

浙公网安备 33010602011771号