team2012-F3-sol-0005
从 Trac 迁移的文章
这是从旧校内 Wiki 迁移的文章,可能存在一些样式问题,您可以向 memset0 反馈。
原文章内容如下:
{{{
题意:计算(n+1)*(m+1)的格板上的所有三角形数目
解法:选取三角形三个顶点有C((n+1)*(m+1), 3)种,再减去三点共线的情况。
三点共线的情况有:
此线斜率大于零、斜率小于零、斜率为零、斜率为无穷
后两种由(m+1)*C(n+1,3)和(n+1)*C(m+1,3)得到;由对称性,前两种个数相同,且每条线段可以视为从(0,0)到(i,j)的线段平移得到,枚举(i,j)即可,中间连线上的点为gcd(i,j)-1
}}}
{{{
#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
typedef long long LL;
int n, m;
LL gcd(LL a, LL b)
{
while(b)
{
LL c = a % b;
a = b;
b = c;
}
return a;
}
LL gao()
{
LL ret = 0;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
LL g = gcd(i, j);
if(--g)
ret += g*(n-i+1)*(m-j+1);
}
return ret;
}
LL c3(LL a)
{
return a*(a-1)/2*(a-2)/3;
}
int main()
{
while(cin>>n>>m)
{
LL ans = c3((n+1)*(m+1));
ans -= (n+1) * c3(m+1);
ans -= (m+1) * c3(n+1);
ans -= 2 * gao();
cout<<ans<<endl;
}
return 0;
}
}}}
题意:计算(n+1)*(m+1)的格板上的所有三角形数目
解法:选取三角形三个顶点有C((n+1)*(m+1), 3)种,再减去三点共线的情况。
三点共线的情况有:
此线斜率大于零、斜率小于零、斜率为零、斜率为无穷
后两种由(m+1)*C(n+1,3)和(n+1)*C(m+1,3)得到;由对称性,前两种个数相同,且每条线段可以视为从(0,0)到(i,j)的线段平移得到,枚举(i,j)即可,中间连线上的点为gcd(i,j)-1
#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
typedef long long LL;
int n, m;
LL gcd(LL a, LL b)
{
while(b)
{
LL c = a % b;
a = b;
b = c;
}
return a;
}
LL gao()
{
LL ret = 0;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
LL g = gcd(i, j);
if(--g)
ret += g*(n-i+1)*(m-j+1);
}
return ret;
}
LL c3(LL a)
{
return a*(a-1)/2*(a-2)/3;
}
int main()
{
while(cin>>n>>m)
{
LL ans = c3((n+1)*(m+1));
ans -= (n+1) * c3(m+1);
ans -= (m+1) * c3(n+1);
ans -= 2 * gao();
cout<<ans<<endl;
}
return 0;
}