题面:
分火腿
(hdogs.pas/.c/.cpp)
时间限制:1s;内存限制 64MB
题目描述:
小月言要过四岁生日了,她的妈妈为她准备了n根火腿,她想将这些火腿均分给m位小朋友,所以她可能需要切火腿。为了省事,小月言想切最少的刀数,使这n根火腿分成均等的m份。请问最少要切几刀?
输入描述:
第一行一个整数T,表示有T组数据。
接下来T组数据,每组共一行,有两个数字n,m。
输出描述:
每组数据一行,输出最少要切的刀数。
样例输入:
2
2 6
6 2
样例输出:
4
0
数据范围:
100%的数据保证T<=1000;n,m<=2147483647。
不得不说,这道题,我确实没看懂……只有特判一下,输出0骗分滚粗QAQ
试(事)♂后,才发现其实超级简单啊……
思路如下:
我们把这些火腿看成是一根大火腿,不过一些位置已经被切过了。
根据题意,我们要把这根大火腿平均切。既然如此,那我们每次切的位置一定是确定的,并且切了m-1刀。
这样,我们需要做的就是判断一下那些位置已经被切过了,不需要我们再切,再将这些位置有几个记录一下,最后减去就好了。
可以想象,那些需要切的位置与已经切好的位置重合的条件就是此时需要切的位置是需要切的长度和已经切好的长度的位置的最小公倍数的整数倍。(需要切的长度就是平分后的每个人得到长度,已经切好的长度就是每根火腿的长度)
设每根火腿长度为1,则平分后每个人得到的长度是n/m(n根火腿,m个人),设最小公倍数为k。那么1与n/m的最小公倍数k=(n*m/gcd(n,m))/m=n/gcd(n,m)。(这是分数的最大质因子求法)那么重合被切的位置就有(n/k)个,也就是(gcd(n,m)-1)个。(注意:这里减一的原因是我们把最后一个也算进去了,也就是这根大火腿的尾端。被算进去的原因也很简单,尾端是一定能被我们恰好切的,因为n一定是1和(n/m)的公倍数。至于为什么首端为什么没有被算进去是因为0不是1和(n/m)的公倍数。)
那么只要输出m-1-(gcd(n,m)-1)=m-gcd(n,m)就好啦~
代码如下:
#includeusing namespace std;int n,m,T;template inline void read(T &x){ x=0;int f=0;char ch=getchar(); while(ch<'0'||ch>'9'){ f|=(ch=='-'); ch=getchar(); } while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } x=f ? -x:x; return;}inline int Gcd(int x,int y){ int c=x%y; while(c!=0) { x=y; y=c; c=x%y; } return y;}int main(){// freopen("hdogs.in","r",stdin);// freopen("hdogs.out","w",stdout); read(T); while(T--) { read(n);read(m); if(n%m==0)printf("0\n");//特判 else printf("%d\n",m-Gcd(n,m)); }// fclose(stdin);// fclose(stdout); return 0;}