【51nod1415】切方块(数论毒瘤)(gcd)

本文深入探讨了一种复杂的三维几何问题,通过详细的数学推导和算法实现,提供了一个高效解决此类问题的方法。以具体实例15x10x6的立方体为例,详细解析了如何计算特定条件下的格点数目,揭示了算法背后的数学原理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

传送门


题解:

刚拿到的时候还以为是什么类欧几里得神仙题。

这道题要抄代码倒是很好抄,推导很麻烦。

首先当 g c d gcd gcd不为 1 1 1的时候,设 g = g c d ( a , b , c ) g=gcd(a,b,c) g=gcd(a,b,c),我们可以轻易转化为 g 2 g^2 g2个小的平面来算。

F ( a , b , c ) F(a,b,c) F(a,b,c)表示当 g c d ( a , b , c ) = 1 gcd(a,b,c)=1 gcd(a,b,c)=1的时候的答案,先给一个结论,只想抄代码的可以拿了直接滚:

2 ⋅ F ( a , b , c ) = a ⋅ b + b ⋅ c + c ⋅ a − g c d ( a , b ) ⋅ g c d ( a , c ) ⋅ g c d ( b , c ) 2\cdot F(a,b,c)=a\cdot b+b\cdot c+c\cdot a-gcd(a,b)\cdot gcd(a,c)\cdot gcd(b,c) 2F(a,b,c)=ab+bc+cagcd(a,b)gcd(a,c)gcd(b,c)

我们发现一个问题,在三者 g c d = 1 gcd=1 gcd=1的情况下,两两的 g c d gcd gcd不一定为 1 1 1

接下来以 a = 15 , b = 10 , c = 6 a=15,b=10,c=6 a=15,b=10,c=6为例子进行探讨。(官方题解就是这个例子)

开始官方题解的神仙推导:

首先拿到主视图(用几何画板硬生生画出来的):

在这里插入图片描述

底为 a a a高为 b b b,首先看图中紫色的部分,这部分中所有被染到的格子(只染到顶点不算)在截面中都会被切掉一次。

显然染掉的格子总数为 S 1 = a ⋅ b + a + b − g c d ( a , b ) 2 S_1=\dfrac{a\cdot b+a+b-gcd(a,b)}{2} S1=2ab+a+bgcd(a,b)


简单证明一下:

显然我们可以根据对称性来考虑,则 S 1 = a ⋅ b + k 1 2 S_1=\dfrac{a\cdot b+k_1}{2} S1=2ab+k1,其中 k 1 k_1 k1为对角线穿过的格子总数。

显然 k 1 k_1 k1可以考虑穿过了几次横轴和纵轴,一共 a + b a+b a+b次,有几次是横轴和纵轴一起穿过的,一共 g c d ( a , b ) gcd(a,b) gcd(a,b)次,则 k 1 = a + b − g c d ( a , b ) k_1=a+b-gcd(a,b) k1=a+bgcd(a,b)


然后,我们把主视图向后推 c c c个单位,把所有 c c c条截面上的交线画出来:
在这里插入图片描述
除了这里紫色区域的斜边外,所有剩下线段在主视图中交上了的格子全部都会在平移后对答案产生贡献需要计算。

假设线段从上到下依次为第 1 1 1条到第 c c c条,其中第 i i i条线段交的格子数量为 k i k_i ki

则答案为 F ( a , b , c ) = S 1 + ∑ i = 2 c k i F(a,b,c)=S_1+\sum\limits_{i=2}^ck_i F(a,b,c)=S1+i=2cki

2 ⋅ F ( a , b , c ) = a b − k 1 + 2 ⋅ ∑ i = 1 c k i 2\cdot F(a,b,c)=ab-k_1+2\cdot \sum\limits_{i=1}^ck_i 2F(a,b,c)=abk1+2i=1cki

仿照计算 k 1 k_1 k1的时候,对于所有 k i k_i ki,我们计算他横跨了多少行,多少列,跨过多少个顶点。

对于 i i i,分别设以上三个量为 r i , c i , p i r_i,c_i,p_i ri,ci,pi

为了方便,以下全部都求 2 ⋅ F ( a , b , c ) 2\cdot F(a,b,c) 2F(a,b,c)

顶点我们规定必须严格在紫色区域内。

表达式为 2 ⋅ F ( a , b , c ) = a b − k 1 + 2 c + 2 ⋅ ( ∑ i = 1 c r i + ∑ i = 1 c c i − ∑ i = 1 c p i ) 2\cdot F(a,b,c)=ab-k_1+2c+2\cdot(\sum_{i=1}^cr_i+\sum_{i=1}^cc_i-\sum_{i=1}^c p_i) 2F(a,b,c)=abk1+2c+2(i=1cri+i=1ccii=1cpi)

则现在要求 ∑ i = 1 c r i , ∑ i = 1 c c i , ∑ i = 1 c p i \sum\limits_{i=1}^cr_i,\sum\limits_{i=1}^cc_i,\sum\limits_{i=1}^cp_i i=1cri,i=1cci,i=1cpi

现在算一下 ∑ c i \sum c_i ci ∑ r i \sum r_i ri同理。

这个地方我觉得官方题解在口胡,我说得稍微详细一点。

直接考虑每条线的横坐标坐标可以得到 c i = ⌈ ( c − i + 1 ) ⋅ a c ⌉ c_i=\lceil\dfrac{(c-i+1)\cdot a}{c}\rceil ci=c(ci+1)a,则:

∑ i = 1 c c i = ∑ i = 1 c ⌈ i ⋅ a c ⌉ = ∑ i = 1 c i ⋅ a c + ∑ i = 1 c c − ( i ⋅ a ) % c c = ∑ i = 1 c i ⋅ a c + ∑ i = 1 c i ⋅ a % c c \begin{aligned} \sum_{i=1}^cc_i&=&&\sum_{i=1}^c\lceil\frac{i\cdot a}{c}\rceil\\ &=&&\sum_{i=1}^c\frac{i\cdot a}{c}+\sum_{i=1}^c\frac{c-(i\cdot a)\%c}{c}\\ &=&&\sum_{i=1}^c\frac{i\cdot a}{c}+\sum_{i=1}^c\frac{i\cdot a\%c}{c}\\ \end{aligned} i=1cci===i=1cciai=1ccia+i=1ccc(ia)%ci=1ccia+i=1ccia%c

两部分乘 2 2 2算一下:

2 ⋅ ∑ i = 1 c i ⋅ a c = ( c + 1 ) ⋅ a 2 ⋅ ∑ i = 1 c i ⋅ a % c c = g c d ( a , c ) ⋅ ( c g c d ( a , c ) − 1 ) = c − g c d ( a , c ) \begin{aligned} 2\cdot \sum_{i=1}^c\frac{i\cdot a}{c}&=&&(c+1)\cdot a\\ 2\cdot \sum_{i=1}^c\frac{i\cdot a\%c}{c}&=&&gcd(a,c)\cdot(\frac{c}{gcd(a,c)}-1)=c-gcd(a,c) \end{aligned} 2i=1ccia2i=1ccia%c==(c+1)agcd(a,c)(gcd(a,c)c1)=cgcd(a,c)

有: ∑ i = 1 c c i = a ⋅ c + a + c − g c d ( a , c ) \sum_{i=1}^cc_i=a\cdot c+a+c-gcd(a,c) i=1cci=ac+a+cgcd(a,c)

同理 ∑ i = 1 c r i = b ⋅ c + b + c − g c d ( b , c ) \sum_{i=1}^cr_i=b\cdot c+b+c-gcd(b,c) i=1cri=bc+b+cgcd(b,c)

然后考虑算 ∑ i = 1 c p i \sum_{i=1}^cp_i i=1cpi

算一下紫色区域内部三线交点的个数,还是考虑计算全图,加上对角线上的 g c d ( a , b ) − 1 gcd(a,b)-1 gcd(a,b)1个点之后除以 2 2 2

发现一共有 g c d ( a , b ) ⋅ g c d ( a , c ) − 1 gcd(a,b)\cdot gcd(a,c)-1 gcd(a,b)gcd(a,c)1条线上有 g c d ( b , c ) gcd(b,c) gcd(b,c)个点,其中有 g c d ( a . c ) − 1 gcd(a.c)-1 gcd(a.c)1条线上有 1 1 1个点不在内部。

2 ⋅ ∑ i = 1 c p i = ( g c d ( a , b ) ⋅ g c d ( a , c ) − 1 ) ⋅ g c d ( b , c ) − ( g c d ( a , c ) − 1 ) + g c d ( a , b ) − 1 = g c d ( a , b ) ⋅ g c d ( a , c ) ⋅ g c d ( b , c ) + g c d ( a , b ) − g c d ( b , c ) − g c d ( a , c ) \begin{aligned} 2\cdot \sum_{i=1}^cp_i&=&&(gcd(a,b)\cdot gcd(a,c)-1)\cdot gcd(b,c)-(gcd(a,c)-1)+gcd(a,b)-1\\ &=&&gcd(a,b)\cdot gcd(a,c)\cdot gcd(b,c)+gcd(a,b)-gcd(b,c)-gcd(a,c) \end{aligned} 2i=1cpi==(gcd(a,b)gcd(a,c)1)gcd(b,c)(gcd(a,c)1)+gcd(a,b)1gcd(a,b)gcd(a,c)gcd(b,c)+gcd(a,b)gcd(b,c)gcd(a,c)

把上面一大坨东西合并起来


代码:

#include<bits/stdc++.h>
#define ll long long
#define re register
#define cs const

cs int mod=1e9+7,inv2=mod+1>>1;

ll a,b,c;

signed main(){
	int T;std::cin>>T;
	while(T--){
		std::cin>>a>>b>>c;
		ll g=std::__gcd(a,std::__gcd(b,c));
		a/=g,b/=g,c/=g;
		ll ab=std::__gcd(a,b),bc=std::__gcd(b,c),ac=std::__gcd(a,c);
		a%=mod,b%=mod,c%=mod;
		ab%=mod,bc%=mod,ac%=mod;
		g%=mod,g=g*g%mod*inv2%mod;
		std::cout<<(a*b+b*c+a*c-ab*bc%mod*ac%mod+mod)%mod*g%mod<<"\n";
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值