BZOJ-3505 [Cqoi2014]数三角形(计数+容斥)
作者:互联网
题目描述
给定一个 \(n\times m(1\leq n,m\leq 1000)\) 的网格,计算三点都在格点上的三角形共有多少个。注意三角形的三点不能共线。
分析
一共有 \((n+1)(m+1)\) 个点,所以任选三个点的总方案数为 \(\dbinom{(n+1)(m+1)}{3}\)。
三点共线的方案数等于横着的 \(+\) 竖着的 \(+\) 斜着的。
横着的方案数有 \((n+1)·\dbinom{m+1}{3}\),竖着的方案数有 \((m+1)·\dbinom{n+1}{3}\)。
考虑如何计算斜着的方案数,斜着的直线按斜率正负分为两种,而且两种方案数相同,所以只需要算出斜率为正的方案数再乘 \(2\) 即可。
假设线段 \(AB\) 平行于 \(x\) 轴,长度为 \(i\),线段 \(BC\) 平行于 \(y\) 轴,长度为 \(j\),则线段 \(AC\) 上的整点数量为 \(\gcd(i,j)+1\)。
枚举 \(A\)、\(B\) 两点的横坐标之差 \(i\),纵坐标之差 \(j\),则两点连线上的整点数量为 \(\gcd(i,j)+1\)(不算两端点的话数量为 \(\gcd(i,j)-1\))。对于每组横坐标之差为 \(i\),纵坐标之差为 \(j\) 的点对,先取两端点,再在两端点之间的 \(\gcd(i,j)-1\) 个点中任选一个作为第三个点,方案数为 \(\gcd(i,j)-1\)。
像这样横坐标之差为 \(i\),纵坐标之差为 \(j\) 的点对共有 \((n-i-1)(m-j+1)\) 个,则斜着的方案数为:
\[ans=\sum_{i=1}^{n}\sum_{j=1}^{m}(n-i+1)(m-j+1)(\gcd(i,j)-1) \]代码
#include<bits/stdc++.h>
using namespace std;
int n,m;
long long C[1000100][4];
void init()
{
C[0][0]=1;
for(int i=1;i<=(n+1)*(m+1);i++)
{
C[i][0]=1;
for(int j=1;j<=3;j++)
C[i][j]=C[i-1][j-1]+C[i-1][j];
}
}
int main()
{
cin>>n>>m;
init();
long long ans=C[(n+1)*(m+1)][3]-(n+1)*C[(m+1)][3]-(m+1)*C[(n+1)][3];
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
ans=ans-2*(n-i+1)*(m-j+1)*(__gcd(i,j)-1);
cout<<ans<<endl;
return 0;
}
标签:方案,gcd,int,容斥,之差,long,3505,Cqoi2014,dbinom 来源: https://www.cnblogs.com/DestinHistoire/p/13960204.html