首页 > 试题广场 >

猴子分桃

[编程题]猴子分桃
  • 热度指数:3321 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 32M,其他语言64M
  • 算法知识视频讲解
老猴子辛苦了一辈子,给那群小猴子们留下了一笔巨大的财富——一大堆桃子。老猴子决定把这些桃子分给小猴子。
第一个猴子来了,它把桃子分成五堆,五堆一样多,但还多出一个。它把剩下的一个留给老猴子,自己拿走其中的一堆。
第二个猴子来了,它把桃子分成五堆,五堆一样多,但又多出一个。它把多出的一个留给老猴子,自己拿走其中的一堆。
后来的小猴子都如此照办。最后剩下的桃子全部留给老猴子。
这里有n只小猴子,请你写个程序计算一下在开始时至少有多少个桃子,以及最后老猴子最少能得到几个桃子。

输入描述:
输入包括多组测试数据。
每组测试数据包括一个整数n(1≤n≤20)。
输入以0结束,该行不做处理。


输出描述:
每组测试数据对应一行输出。
包括两个整数a,b。
分别代表开始时最小需要的桃子数,和结束后老猴子最少能得到的桃子数。
示例1

输入

5
1
0

输出

3121 1025
1 1

  从题目中来看,小猴子每次将桃子均分为 5 堆时都会多出来 1 个,所以为了方便计算,我们在最开始时就借给猴子们 4 个桃子,这样的话,每次都可以刚好均分为 5 堆。

  假设在开始时就有 X 个桃子,借给猴子们 4 个后,此时就一共有 X+4 个桃子。
  当第一只小猴子来时,它将 X+4 个桃子均分为 5 堆后,拿走 (X+4)*(1/5) 个,剩余 (X+4)*(4/5) 个桃子。在这里,有人可能会有疑问:给老猴子的那个桃子去哪里呢?其实,小猴子拿的那一部分就包括了这一个桃子,并且小猴子也没有多得桃子,它实际上得到的桃子数为 (X+4)*(1/5) - 1 = (X-1)*(1/5) ,这和在不借给它们 4 个桃子的情况下得到的数量是一样的,不过此时剩余的桃子数相较于之前多了 (X+4)*(4/5) - (X-1)*(4/5) = 4 个,但这样就恰巧保证了下一只小猴子分桃时,也能刚好均分为 5 堆。由此可见,所有的小猴子都不会多得桃子,老猴子也不会少得桃子,并且每次小猴子都能刚好将桃子均分为 5 堆,而借给的那 4 个桃子每次都在剩余的那部分里,最后去除即可。
  当第二只小猴子来时,它将 (X+4)*(4/5) 个桃子均分为 5 堆后,拿走 (X+4)*(4/5)*(1/5) 个,剩余 (X+4)*(4/5)^2 个桃子。
  当第三只小猴子来时,它将 (X+4)*(4/5)^2 个桃子均分为 5 堆后,拿走 (X+4)*(4/5)^2*(1/5) 个,剩余 (X+4)*(4/5)^3 个桃子。
  .....
  依次类推,当第 n 只小猴子(最后一只小猴子)来时,它将 (X+4)*(4/5)^(n-1) 个桃子均分为 5 堆后,拿走 (X+4)*(4/5)^(n-1)*(1/5) 个,剩余 (X+4)*(4/5)^n 个桃子。

  为了满足题目最后的要求,也就是要保证最后剩余的桃子数最少且为整数,那么当 X+4 = 5^n 时,刚好满足要求,此时可得出:
(1)开始时的总桃子数X = 5^n - 4
(2)老猴子最后能得到的桃子数n + (X+4)*(4/5)^n - 4 = n + 4^n - 4
  因为老猴子能得到的桃子主要有两个来源:一是每个小猴子都要给一个,有 n 只小猴子,就可以得到 n 个;二是最后剩余的桃子都归老猴子所有,从上面最后一次的结果来看,一共剩余了 (X+4)*(4/5)^n 个桃子,但是这里面包括我们最早借给它们的 4 个,实际上剩余的桃子数为 (X+4)*(4/5)^n - 4 ,所以最后总共能得到的桃子数就是 n + (X+4)*(4/5)^n - 4

发表于 2019-10-24 18:49:23 回复(4)
纯数学题,思路与前面人的思路不太一样,不用借桃子,直接根据题意来进行求解,设最少需要桃子X个:
第一次经过题目的处理剩余桃子数目为:4/5(X-1)=(4/5)*X-(4/5);
第二次剩余桃子个数为:4/5(4/5(X-1)-1)=((4/5)^2)*X-(4/5)^2-(4/5);
第三次剩余桃子个数为:4/5(4/5(4/5(X-1)-1)-1)=((4/5)^3)*X-(4/5)^3-(4/5)^2-(4/5);
......
依次类推,经过n只猴子的类似处理,剩余桃子数为:
4/5(4/5(4/5(....(4/5(X-1)...)-1)-1)-1)=((4/5)^n)*X)-(4/5)^n-(4/5)^(n-1)-...-(4/5)
=((4/5)^n)*X)-4[1-(4/5)^n]
=(X+4)*(4/5)^n-4
因此,同前人的推导一致,最终,只需要满足x+4的值为5^n次方则可以保证最后能得到一个整数,满足题目的要求,因此,代码如下:
#include<iostream>
#include<cmath>
using namespace std;
 
int main()
{     int n;     
while(cin >> n)     
{         
if(n == 0)             
break;         
else        
{             
cout <<pow(5, n) - 4 <<" "<<pow(4, n) + n - 4 << endl;         
}     
}             
return 0;
}

发表于 2019-04-22 13:30:46 回复(3)
/**
 * 思路:因为每次分5堆都会多出来1个,所以我们借给猴子们4个,以致每次都可以刚好分成5堆
 *     并且,每次给老猴子的桃子都不在我们借出的那4个中,这样最后减掉4就可以得到结果。
 *   假设最初由x个桃子,我们借给猴子4个,则此时有x+4个,
 *   第一个猴子得到(x+4)/5,剩余(x+4)*(4/5)个
 *   第二个猴子分完后剩余(x+4)*(4/5)^2个
 *   第三个猴子分完后剩余(x+4)*(4/5)^3个
 *   依次类推,最后一个猴子分完后剩余(x+4)*(4/5)^n
 *   要满足最后剩余的为整数,并且x最小,则当 x+4=5^n时,满足要求
 *   此时,x=5^n-4;
 *   老猴子得到的数量为:old = (x+4)*(4/5)^n + n - 4
 *                     = 4^n + n - 4
 *   最后加n是因为不是剩余多出来的一个,而是小猴子给的,比如桃子是有6个,小猴子本身只能拿一个,我们借给4个,小猴就能拿两个,那多出来的哪一个给老猴子,和之前6个整除五余1一个道理        
 *   最后老猴子减4是还给我们借给它们的那4个
 *     
 */
import java.util.Scanner;
 
public class Main {
 
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        long n = 0;
        while(sc.hasNext()){
            n = sc.nextInt();
            if(n == 0)
                break;
            long a = (long)Math.pow(5, n);
            long b = (long)Math.pow(4, n);
            System.out.println((a-4)+" "+(b-4+n));
        }
    }
}

发表于 2016-08-26 16:57:13 回复(1)
package xd.zm.nowcoder;
/**
 * 思路:因为每次分5堆都会多出来1个,所以我们借给猴子们4个,以致每次都可以刚好分成5堆
 * 	   并且,每次给老猴子的桃子都不在我们借出的那4个中,这样最后减掉4就可以得到结果。
 *   假设最初由x个桃子,我们借给猴子4个,则此时有x+4个,
 *   第一个猴子得到(x+4)/5,剩余(x+4)*(4/5)个
 *   第二个猴子分完后剩余(x+4)*(4/5)^2个
 *   第三个猴子分完后剩余(x+4)*(4/5)^3个
 *   依次类推,最后一个猴子分完后剩余(x+4)*(4/5)^n
 *   要满足最后剩余的为整数,并且x最小,则当 x+4=5^n时,满足要求
 *   此时,x=5^n-4;
 *   老猴子得到的数量为:old = (x+4)*(4/5)^n + n - 4 
 *   			       = 4^n + n - 4
 *   最后老猴子减4是还给我们借给它们的那4个
 * 	    
 */
import java.util.Scanner;

public class Main {

	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		long n = 0;
		while(sc.hasNext()){
			n = sc.nextInt();
			if(n == 0)
				break;
			long a = (long)Math.pow(5, n);
			long b = (long)Math.pow(4, n);
			System.out.println((a-4)+" "+(b-4+n));
		}
	}
}


发表于 2016-01-18 17:51:10 回复(0)

设原来有x个桃子,假设供5个小猴子,因为第一只猴子拿一个给老猴子,正好可以分成5堆,
所以我们借给猴子4个桃子,那么正好可以分成5堆,第一个猴子就拿了其中一堆(包括老猴子的一个),但是,它并没有多得桃子,就是(x+4)× (1/5) = (x-1)*1/5 
第1个小猴子拿走一份,这一份包括自己的那部分和老猴子的一个。那么剩余桃子是(x+4)*(4/5)。这剩余的桃子中多了4个。由于每次分因为要给老猴子一个,所以算上多出来的4个,每次均能5等分。 那么分5次后剩余桃子为(x+4)*(4/5)^5,显然保证x最小,且剩余为整数那么x+4 = 5^5 => x = 5^5 - 4 这样得到总的桃子数。而老猴子的桃子为每次小猴子分给老猴子的一个桃子加上剩余没分完的桃子,并减去最初多添加进来的4个桃子。 为 5 + (x+4)*(4/5)^5 - 4 。 这里5换成n即得到最终的公式。

发表于 2015-09-29 15:59:08 回复(6)
不用借桃子,那样只是让公式简单,设最开始桃子数量为x,直接纯数学推导剩余桃子的数量,利用错位相减法简化式子,一样能求出来:

// write your code here cpp
#include<iostream>
#include<math.h>
using namespace std;
int main() {
    long long n;
    while (cin >> n) {
        if (n == 0)
            break;
        long long start=pow(5,n)-4;
        long long old =n+pow(4,n)-4;
        cout<<start<<' '<<old<<endl;
    }
    return 0;
}


发表于 2022-10-22 16:59:05 回复(0)
import java.util.*;
public class Main{
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        while(sc.hasNext()){
            int n = sc.nextInt();
            if(n == 0){
                break;
            }
            long a = (long)(Math.pow(5,n) - 4);
            long b = (long)( n + Math.pow(4,n) - 4);
            System.out.println(a +" " + b);
        }
    }
}

发表于 2022-04-28 22:19:29 回复(0)
终于找到一种非公式也能通过的方法,让每次的结果依赖于上一次的结果进行时间上的优化
#include <iostream>
#include <vector>
using namespace std;

int main()
{
    int n = 0;
    vector<long long> numv(21, 0);
    vector<long long> rv(21, 0);
    long long start = 0;

    for (int i = 1; i <= 20; ++i)
    {
        for (long long k = start; ; ++k)
        {
            int r = 0;
            int tmp = i;
            long long num = 20 * k + 1;

            while (tmp--)
            {
                num = (num - 1) / 5 * 4;//拿走一次后剩下的桃子
                ++r;
                if (num % 5 != 1)//不能再继续分了
                    break;
            }
            if (tmp == 0)
            {
                cout << start  << " " << k << endl;
                numv[i] = 20 * k + 1;
                rv[i] = r + num;
                start = k * 5;
                break;
            }
        }
    }

    cin >> n;
    while (n != 0)
    {
        cout << numv[n] << " " << rv[n] << endl;
        cin >> n;
    }

    return 0;
}


发表于 2022-04-28 11:27:55 回复(0)
这数学题可太恶心了
#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;

 int main()
 {
     int n;
     while (cin>>n)
     {
         if(n==0)
             break;
         long long sum,sum1;
         sum = pow(5,n)-4;
         sum1 = pow(4,n)+n-4;
         cout<<sum<<" "<<sum1<<endl;
     }
     return 0;
 }


发表于 2021-08-03 00:38:48 回复(0)
公式类推题
因为每次分5堆都会多出来1个,所以我们借给猴子们4个,以致每次都可以刚好分成5堆。并且,每次给老猴子的桃子都不在我们借出的那4个中,这样最后减掉4就可以得到结果。
假设最初由x个桃子,我们借给猴子4个,则此时有x+4个:
第一个猴子得到(x+4)/ 5,剩余(x+4)*(4/5)个
第二个猴子分完后剩余(x+4)* (4/5)^2个
第三个猴子分完后剩余(x+4)* (4/5)^3个
依次类推,第n个猴子分完后剩余(x+4)*(4/5)^n
要满足最后剩余的为整数,并且x最小,则当 x+4=5^n时,满足要求;此时,x=5^n - 4;
老猴子得到的数量为(代入上式):(x+4)*(4/5)^n + n - 4 = 4^n + n - 4
(最后的 +n是因为每个小猴子都会多出一个给老猴子,-4是还了借的4个)
#include <iostream>
#include <algorithm>
using namespace std;
int main(){
    int n;
    while(cin >> n){
        if(n == 0){
            continue;
        }
        long a = pow(5, n) - 4;
        long b = pow(4, n) + n - 4;
        cout << a << " " << b << endl;
    }
    return 0;
}

编辑于 2020-07-16 15:47:09 回复(1)
#include<iostream>
#include<vector>
#include<string>
#include<algorithm>
#include<functional>
#include <map>
#include <set>
#include <unordered_set>
#include <unordered_map>
#include <exception>

using namespace std;

void seperatePeach(int n)
{
}

int main(int argc,char** argv)
{
	int n;
	while (cin >> n && n > 0)
	{
		cout << (long)pow(5, n) - 4 << " " << (long)pow(4, n) + n - 4 << endl;
	}
	return 0;
}

发表于 2017-07-07 22:43:04 回复(0)
import java.util.*;
public class Main {
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		while (sc.hasNext()) {
			int n = sc.nextInt();
			if(n == 0) break;
			System.out.println((long)(Math.pow(5, n) - 4) + " " + (long)(Math.pow(4, n) + n - 4));
		}
	}
}

发表于 2016-10-16 20:20:21 回复(0)
#include<stdio.h>
#include<math.h>
    
int main()
{
    unsigned long n, a, b;
    while(scanf("%lu", &n)){
        if(n == 0) break;
        
        a = (unsigned long)pow(5, (double)n);
        b = (unsigned long)pow(4, (double)n);
        
        printf("%lu %lu\n", a-4, b-4+n);
    }
    return 0;
}
编辑于 2015-09-11 12:51:02 回复(0)
import java.util.Scanner;

// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        // 注意 hasNext 和 hasNextLine 的区别
        while (in.hasNextInt()) { // 注意 while 处理多个 case
            int n=in.nextInt();
            if(n==0){
                break;
            }else{
                long sum=(long)Math.pow(5.0,n)-4;
                long yu=(long)Math.pow(4.0,n)-4+n;
                System.out.print(sum+" ");
                System.out.println(yu);
            }
        }
    }
}


编辑于 2024-03-18 15:20:59 回复(0)
发表于 2022-05-19 09:44:33 回复(0)
// write your code here cpp
/*
*每次分5堆都会多出来1个,那么借给猴子们4个桃子,此时每次正好可以分成5堆
*(假设每次分给猴子们的桃子都不是借给他们的那4个桃子,最后-4就可以得到结果了)
*假设最初有桃子x个,借给猴子们4个,总共有x+4个
*那么第一个小猴子得到(x+4)*(1/5),剩余(x+4)*(4/5)个
*那么第二个小猴子得到(x+4)*(4/5)*(1/5),剩余(x+4)*(4/5)^2个
*那么第三个小猴子得到(x+4)*(4/5)^2*(1/5),剩余(x+4)*(4/5)^3个
*以此类推,第n个猴子达到(x+4)*(4/5)^(n-1)*(1/5),剩余(x+4)*(4/5)^n个
*要满足最后剩余的桃子为整数,并且x最小,则当且仅当x+4=5^n,即x=5^n-4;
*因此老猴子最后得到的桃子数为(5^n-4+4)*(4/5)^n+n-4=4^n+n-4
*(+n是因为每个小猴子都会将多出来的一个给老猴子,-4是刚开始借给小猴子的)
*/
#include <iostream>
#include <algorithm>
using namespace std;
int main()
{
    int n;
    while(cin>>n)
    {
        if(n==0)//0个猴子,结束此次循环,进行下一次循环输入
        {
            continue;
        }
        long a=pow(5,n)-4;
        long b=pow(4,n)+n-4;
        cout<<a<<" "<<b<<endl;
    }
    return 0;
}

发表于 2021-03-22 11:18:05 回复(0)
每个小小猴子都会留一个给老猴子,所以要让第n个小猴子有桃子,最后至少剩六个桃子,依次便可算出最初需要的桃子数
发表于 2017-04-26 10:42:00 回复(0)
这个很奇怪。答案如果输入为1,输出为1 1 ,表明1只猴子可以至少有1个桃子,也就是说小猴子一个没拿走,全给老猴子了。  那么2只猴子还可以至少2个,老猴子拿2个呢。然后每次小猴子都没拿走,反正分不匀。
发表于 2016-08-30 10:23:32 回复(0)
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.util.Scanner;

/**
 * Created by novas on 15-10-9.
 */

public class Main {
public static double getLeft(double m,int n)
{
    double sum=m;
    for(int i=1;i<n;i++)
    {
        m=(m*5+1)/4;
        sum=sum+m;
    }
    return sum;
}
    public static void main(String[] args) throws Exception
    {

        double a=1,b=1,c=0;
        double temp=0;
       // Scanner scanner=new Scanner(System.in);
        BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
        int n=Integer.valueOf(br.readLine());

        while(n!=0)
        {

           for(int i=0;i<n;i++) {
               a=(long)Math.pow(4,i);
               b=b*5;
               c=a-1;
               temp=temp*5+a;
           }
            DecimalFormat df=new DecimalFormat("0");
           double count=(b*c+a+temp)/a-1;
            System.out.println(df.format(count)+" "+df.format(count-getLeft(c,n)));
            n=Integer.valueOf(br.readLine());
            a=1;
            b=1;
            c=0;
            temp=0;
        }
    }
}


发表于 2015-10-17 14:51:24 回复(0)
import java.util.Scanner;

public class Main {
public static void main(String[] args) {
Scanner in=new Scanner(System.in);
while(in.hasNext()){
long n=in.nextInt();
if(n==0){
return;
}
long result1=1;
long result2=1;
for(int i=0;i<n;i++){
result1=5*result1;
}
result1=result1/10*10+1;
result2=result1;
for(int i=0;i<n;i++){
result2=result2-(result2/5+1);
}
result2=result2+n;
System.out.println(result1+" "+result2);
}
}

}
发表于 2015-09-09 20:09:40 回复(0)