您的位置:首页 > 其它

【CQOI2014】数三角形

2018-01-08 20:02 148 查看
这是一道比较有意思也有意义的题目~

Description



Input

输入一行,包含两个空格分隔的正整数m和n。

Output

输出一个正整数,为所求三角形数量。

Sample Input

输入1:

1 1

输入2:

2 2

Sample Output

输出1:

4

输出2:

76

Data Constraint

对于30%的数据 1<=m,n<=10

对于100%的数据 1<=m,n<=1000

Solution

我们需要仔细思考。

很容易想到直接用容斥原理。

首先算出在这(n+1)*(m+1)个点中,任选三个的方案数,很明显是Sum=C(p,3)[p=(n+1)∗(m+1)]。

但是我们发现在这Sum个数中,有的是三个点连成一条线的,是无法组成一个三角形的,那么我们就要看看可连成一条线的方案数为多少。首先平行于坐标轴的这些线段我们是不用讲的。

我们考虑:确定两个整点(x1,y1),(x2,y2),它们连成的线上拥有的整点数为gcd(x2−x1,y2−y1)+1(包括这两点)

这样必须含有这两点时,在这条线上三个点的方案数就是

gcd(x2−x1,y2−y1)+1[待会会予以证明]


但是我们明显不能枚举两个点,然后我们就可以发现其实只用枚举这个矩阵的长和宽,从而确定对角线。

那么对于一个长和宽分别为i,j的矩阵来说,对角线在整个大矩阵的个数为(n-i)*(m-j);



也就是我们枚举i,j,然后ans−=[gcd(i,j)−1]∗(n−i)∗(n−j)∗2.

因为矩形的对角线有两条,所以要*2.

下面我们来证明为什么数量为gcd(i,j)

For example

我们假设一点为(6,9)



那么拥有的点就是两个,一个是(2,3),一个是(4,6)。

我们可以由斜率相等知道,在这上面的点横纵坐标都可以整除gcd(6,9),

那么第一个点就是(6gcd(6,9),9gcd(6,9))=(2,3),然后从特殊到一般就是(igcd(i,j),jgcd(i,j)).

然后每次加上(igcd(i,j),jgcd(i,j)),直到等于(i,j)为止,

像例子中:(2,3)->(4,6)->(6,9)

那么有多少个呢?就是i/igcd(i,j)或j/jgcd(i,j)那个就是gcd(i,j)个,因为有一个是枚举出来的,所以总个数就是gcd(i,j)−1个.

#include<cstdio>
#include<iostream>
using namespace std;
long long n,m,p;
long long ans;
long long gcd(long long x,long long y)
{
if(x%y==0) return y;
else return gcd(y,x%y);
}
int main()
{
scanf("%lld%lld",&n,&m);
long long i,j,k,l;p=(n+1)*(m+1);
ans=p*(p-1)*(p-2)/6-(m+1)*(n+1)*n*(n-1)/6-(n+1)*(m+1)*m*(m-1)/6;
for (i=1;i<=n;++i)
for (j=1;j<=m;j++)
ans-=2*(n-i+1)*(m-j+1)*(gcd(i,j)-1);
printf("%lld\n",ans);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: