题解 P3166 【[CQOI2014]数三角形】
前言
今天测试考的这道题,但是扫雷把脑子扫炸了,于是没有推出来
我自闭了
本蒟蒻作者数学第一菜,可能说的不清楚,你有两个解决方案:
①憋着
②看别人的
题目
蒟蒻专用传送门
传送门(洛谷)
正题
我们别怕数学题,跟着我一步一步来,可以推出来的!
这道题总体思路是算出三角形的总数,减去共线的三角形个数,即为答案
首先它有多少个三角形呢?
明显是:
为了方便处理,我们先减去 横线上 和 竖线上 的三点共线的三角形
一边有
然后我们考虑斜着的三点共线的三角形,比如这个样子:
我们由于只有
我们枚举了一个点,加上坐标原点,我们就确定了两个点了,还有一个点当然就是这条线段上的坐标为整数的点,现在我们就要算出有多少个这样的点(当然不算坐标原点和枚举的这个点)
首先已知坐标有
那么重新写这条直线的解析式:
我们回头看向
因为是
于是我们求出有
我们把上面那个图拿下来验证:
再乘上之前我们得出的
完了吗?
这只是从左下到右上的线段上的三角形,还有从左上到右下的线段上的三角形需要减:
如图,我们只减了形似于红色的线段上的三角形,但是还有形似于绿色的线段上的三角形
可以轻松证明,把它转一下,就是后者了,所以我们最后要乘个
最后的最后,记得开
代码
//12252024832524
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long LL;
const int MAXN = 1005;
int n,m,n1,m1;
LL s[MAXN][MAXN],ans;
int Read()
{
int x = 0,f = 1;char c = getchar();
while(c > '9' || c < '0'){if(c == '-')f = -1;c = getchar();}
while(c >= '0' && c <= '9'){x = (x*10) + (c^48);c = getchar();}
return x * f;
}
void Put(LL x)
{
if(x > 9) Put(x/10);
putchar(x%10^48);
}
template <typename T>T Max(T x,T y){return x > y ? x : y;}
template <typename T>T Min(T x,T y){return x < y ? x : y;}
template <typename T>T Abs(T x){return x < 0 ? -x : x;}
int gcd(int x,int y)
{
if(!y) return x;
return gcd(y,x%y);
}
LL Cn3(LL x)
{
return x * (x-1) * (x-2) / 6;
}
void solve4()
{
n = n1+1;
m = m1+1;
ans = Cn3(n*m) - m*Cn3(n) - n*Cn3(m);
for(int i = 1;i < n;++ i)
for(int j = 1;j < m;++ j)
ans -= 2ll * (gcd(i,j)-1) * (n - i) * (m - j);
printf("%lld\n",ans);
}
int main()
{
// freopen("triangle.in","r",stdin);
// freopen("triangle.out","w",stdout);
n1 = Read();
m1 = Read();
solve4();
return 0;
}
By The Way
我再也不玩扫雷了,