暑训日记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\)

posted @ 2023-08-23 09:50  CultReborn  阅读(28)  评论(0)    收藏  举报