題解/算法 {1310. 数三角形}

文章讨论了如何计算矩阵中不共线的三个点构成的合法三角形的数量。它指出了一种错误的方法,即计算所有三点组合,然后排除不合法的情况,而推荐的方法是直接计算不同点的选择数。同时,文章强调了考虑斜率不为零的直线时,利用GCD(a,b)+1来确定可能的三角形数量,并避免重复计算的关键点。
摘要由CSDN通过智能技术生成

Link

Solution

首先看一种(错误/麻烦)的做法;

矩阵长为 m m m 高为 n n n, 即有 T = ( m + 1 ) ∗ ( n + 1 ) T = (m+1)*(n+1) T=(m+1)(n+1)个点, 我们选三个点 T 3 T^3 T3, 此时不合法的三角形有几种情况: (一条线, 有两个点重合, 三个点重合), 而且抛去这些情况后, 假如得到 t t t, 那么你需要将 t / ( 3 ! ) t / (3!) t/(3!)后, 才是答案; (因为一个特定的合法三角形, 将三个点线性化后, 他有 3 ! 3! 3!种情况)

这很麻烦, 没必要将总方案设置为 T 3 T^3 T3, 一个三角形的三个点 不需要将他线性化 (也就是比如所有位置ID为1,2,3,4,...,T, 我们选择了三个位置a, b, c; 如果总方案是 T 3 T^3 T3, 则a,b,c会对应有 3 ! 3! 3!个方案, 即abc, acb, bac, ...; 这是没有必要的, 他就去对应一个方案即可);
. 最好的处理是: 我们直接选 3 3 3个坑即可, 即将总方案数设置为 C T 3 C_T^3 CT3 表示选择三个不同的点方案, 毕竟一个合法三角形的三个点 肯定是不同的;

@Delimiter

总方案 C T 3 C_T^3 CT3, 此时不合法的情况 只有(三个点在同一直线上)
1 (斜率垂直) m ∗ C n 3 m * C_n^3 mCn3;
2 (斜率水平) n ∗ C m 3 n * C_m^3 nCm3;
3 (斜率不为0)

重点考虑第三种情况;

性质: 长高为 a ∗ b a*b ab的直角三角形 (注意长度为 a a a是经过了 a + 1 a+1 a+1的点), 有 g c d ( a , b ) + 1 gcd(a,b) + 1 gcd(a,b)+1个方格点 坐落在他的斜边上
证明: 令 g = g c d ( a , b ) , A = a / g , B = b / g g = gcd(a,b), A = a/g, B = b/g g=gcd(a,b),A=a/g,B=b/g, 将长和高都分为了 g g g个长度为 A , B A, B A,B的子段; 于是, 可以发现 斜边也可以分为 g g g的子段 每个子段处于一个 A ∗ B A*B AB的矩形里;

@Delimiter

看一种错误的做法;

对于整个方格矩形边框

d-----c
|     |
a-----b 

只考虑斜率 > 0 > 0 >0的直线 (斜率 < 0 <0 <0的方案 与其相等), 则该直线有两种情况: (1 相交于 a b , b c ab, bc ab,bc) 或者 (2 相交于 a d , d c ad, dc ad,dc); 而且, 该直线与该矩阵边框的交点 肯定位于方格点上;
于是, 将该矩形边框分为两个三角形 a b c , a c d abc, acd abc,acd; 单独考虑 a b c abc abc三角形里面的;

其实这是错误的, 错在: 一个斜率 > 0 >0 >0的直线, 他可能相交于 a d , b c ad, bc ad,bc; 因此不可以将整个矩形边框分为两半来考虑;

而且 更重要的是: 该直线与该矩形边框的交点, 不一定位于方格点上;

意识到这两个错误非常重要;

@Delimiter

再看一种错误思路;

对于一个斜率 > 0 > 0 >0的直线, 假如该矩形里有 k ≥ 3 k \geq 3 k3个点 是位于该直线上的; 令 l , r l,r l,r为两个在该直线上的方格点 且距离最远; 那么由上面的性质, 得由 l , r l,r l,r所确立的三角形 ( l l l向右延伸直线 r r r向下延伸直线, 所构成的三角形), 他的长高 a , b a,b a,b 满足 G C D ( a , b ) = k − 1 GCD(a, b) = k - 1 GCD(a,b)=k1;

但具体 a , b a,b a,b的取值 是有很多种的;

所以, 通过枚举斜边上的点数 k k k; 首先, 他所对应的斜率有很多, 而且即便斜率确定了, 他所对应的三角形长高 a , b a,b a,b 也有很多取值;

@Delimiter

还是基于上面思路: 对于一个斜率 > 0 > 0 >0的直线, 假如该矩形里有 k ≥ 3 k \geq 3 k3个点 是位于该直线上的; 令 l , r l,r l,r为两个在该直线上的方格点 且距离最远; 那么由上面的性质, 得由 l , r l,r l,r所确立的三角形 ( l l l向右延伸直线 r r r向下延伸直线, 所构成的三角形), 他的长高 a , b a,b a,b 满足 G C D ( a , b ) = k − 1 GCD(a, b) = k - 1 GCD(a,b)=k1;

此时, 重点放在 a , b a,b a,b上, 不去考虑这个直线的斜率 因为一旦 a , b a,b a,b确立了 直线斜率也就确立了;
而且, 这个 k k k也不是通过枚举了, 因为 a , b a,b a,b确立了, k k k也就确立了;

于是, 我们枚举长高为 a ∗ b a*b ab的直角三角形 令 k = G C D ( a , b ) + 1 ≥ 2 k = GCD(a,b) + 1 \geq 2 k=GCD(a,b)+12 (即斜边上 k ≥ 3 k \geq 3 k3个点); 这样的三角形, 在整个矩形里, 有 ( m − a + 1 ) ∗ ( n − b + 1 ) (m - a + 1) * (n - b + 1) (ma+1)(nb+1)个 这样的三角形 (形象的说, a ∗ b a*b ab的直角三角形 上下左右移动 会有 ( m − a + 1 ) ∗ ( n − b + 1 ) (m-a+1)*(n-b+1) (ma+1)(nb+1)个不同的位置); 于是, 每个斜边 有 C k 3 C_k^3 Ck3种可能的选择;
. 这又错了… 这样是会有重叠方案的, 比如: k = 4 k = 4 k=4, 我们在某个位置 x , y x,y x,y时, 那么(斜边上最上面的 3 3 3个点) 我们选择了这个方案, 而当我们右移一位再上移一位后 到达 x + 1 , y + 1 x+1,y+1 x+1,y+1的位置 那么(斜边上最下面的 3 3 3个点) 我们也会选择这个方案, 因此重复了;

此时, 你可以固定的 强制的必须选择 (斜边的两个端点), 这样 就不会重复了, 即一个三角形 他的斜边上 不是有 C k 3 C_k^3 Ck3种 而是有 ( k − 2 ) (k-2) (k2)种; 这就对了;

可以理解为: 对于一种不合法的选择: a , b , c a,b,c a,b,c三个点, 其他们形成一个斜率 > 0 >0 >0的直线; 令 l , r l,r l,r为最左侧/最右侧的两个端点;
则此时, l , r l,r l,r形成了一个长高 A , B A,B A,B的三角形, 且该三角形的斜边的端点 就是 l , r l,r l,r;

Code

	long long ans = 0;
    ans += CompPerm_C( M * N, 3);
    ans -= M * CompPerm_C( N, 3);
    ans -= N * CompPerm_C( M, 3);
    for( int i = 2; i <= m; ++i){
        for( int j = 2; j <= n; ++j){
            int g = GCD( i, j);
            if( g < 2){ continue;}
            ans -= (m - i + 1) * (n - j + 1) * 2 * (g - 1);
        }
    }
    cout<<ans;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值