题目链接 https://www.luogu.com.cn/problem/U101928
看了一眼觉得 T1 很水,原来是我想错了,悲惨爆零qwq。 虽然确实挺水的
嗯,首先看一下题目中的一个细节:
将 n 根火腿分成均等的 m 份,不是 m 段 我就死在了这里
也就是说,你可以把两个火腿分成:2/3,1/3,1/3,2/3 四段,其中第二段和第三段可视为一份!
题解
既然如此,我们干脆把 n 根火腿看成一大根好了;
如果我们假设每根火腿的长度为 1,那么这根大火腿的长度为 n;
我们要将其分成均等的 m 份,那么每一份的长度就都是 n/m;
考虑到我们砍一刀就多一段,那么我们最多需要砍 m-1 刀;
还需要注意一个地方:
这 m-1 刀中有若干刀可能就是火腿的接口,也就是说本来这个地方就是断开的,只不过是我们人为的看成是一段而已,但是我们却花费了 1 刀把它切开。
所以我们只需再找出这 m-1 刀中有多少刀正好砍在了两根火腿的接口处,用 m-1 一减就是最后答案了。
可以想到既然有一刀砍在了两根火腿的接口出,那么前面分成的若干段长度为 n/m 的分拼起来可以组成若干根完整的火腿;
也就是说这个接口处必须同时满足是每一根火腿的长度(1)和每一份长度的倍数(n/m) 的倍数,还得是正整数;
因为前面的若干份是由若干根完整的火腿切来的,必须保证同时是它俩的整数倍数;
那么我们就先要求出 lcm ( 1,n/m )来 。
设 k = lcm ( 1,n/m ) = lcm ( m,n ) / m = m * n / gcd ( n,m ) / m = n / gcd ( n,m )
那么这个长度为 n 的大火腿中有 n / k = n / ( n / gcd ( n,m ) ) = gcd ( n,m ) 个 k 的倍数,也就是有这么些个接口符合要求;
但是由于 n 也是 k 的倍数,所以我们把最后一刀(砍在了长度为 n 的大火腿的末端的那一刀)给算上了,实际上是不需要的,那么需要减一,也就是:
gcd ( n,m ) - 1
最后我们再用 m-1 一减,就是最后的答案了:
Ans = ( m - 1 ) - ( gcd ( n,m ) - 1 ) = m - gcd ( n,m );
那么我们直接输出 m - gcd ( n,m ) 就大功告成了!
Code:
#include<iostream> #include<cstdio> using namespace std; int T,n,m; int gcd(int a,int b) { if(b==0) return a; return gcd(b,a%b); } int main() { scanf("%d",&T); while(T--) { scanf("%d%d",&n,&m); printf("%d ",m-gcd(n,m)); } }