2015年小学甲组----game

本文介绍了如何使用编程解决一种特殊的石头、剪刀、布游戏,涉及周期性和最小公倍数的概念。通过辗转相除法计算两个周期的最小公倍数,并在K次游戏中计算获胜次数。

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

第五题 游戏(game)

 

问题描述:

 

今天是星期天,小楠楠来找你玩“石头、剪刀、布游戏”。你正在学习信息学,所以想了一种需要编程来玩的“石头、剪刀、布游戏”。首先,用数字 1,2,3 分别表示出石头、剪刀、布。其次,你确定自己前 N 次“石头、剪刀、布”的出拳方法,下面 N 次再次同样出拳,…,周而复始;也要求楠楠确定他前 M 次的出拳方法,然后周而复始。问第 K 次后,你赢了几次?

 

例如:N=4,你的前 4 次出拳方式是“石头、剪刀、布、布”,用数字表示即:”1

 

2 3  3”。M=5,楠楠前 5 次出拳方式是“剪刀、石头、石头、布、布” ,用

 

数字表示即:”2 1 1 3 3”。K=10 时,情况如下表:

 

轮次

1

2

3

4

5

6

7

8

9

10

你出拳

1

2

3

3

1

2

3

3

1

2

楠楠出拳

2

1

1

3

3

2

1

1

3

3

 

 

 

 

 

 

你共赢了 5 次。

 

输入格式:

 

第一行 3 个整数 N,M,K。分别表示你出拳方式的周期长度、楠楠出拳方式的周期长度和总共玩的次数。

 

第二行有 N 个整数,每个整数为 1、2、3 其中之一。

 

第三行有 M 个整数,每个整数为 1、2、3 其中之一。

 

输出格式:

 

一个整数,表示 K 轮出拳后,你赢的次数。

 

输入样例:

 

 

 

5

6

100

 

 

 

1

3

2

2

1

 

3

3

1

1

1

2

输出样例

 

 

 

29

 

 

 

 

数据范围:

 

 

 

8

个数据: N,M 的范围是[1..100],K 的范围是[1…100,000]。

2

个数据:

 

N,M 的范围是[1..100],K 的范围是[1…1,000,000,000]

 

友情提示)整数数组开的太大(比如 30,000,000)可能会因超空间而得 0 分。


        题目意思就是要我们求k轮后,自己赢的次数。因为自己和楠楠的出拳方式是一直固定的,所以只需枚举就行了。但直接枚举肯定超时。因为自己的出拳方式和楠楠的出拳方式的周期不同,所以又延伸出一个周期问题。转变过来就是成了找最小公倍数的问题。

       找最小公倍数时,我们又可以运用一种快捷方法,辗转相除法。

       辗转相除法求两个数的最大公约数的步骤如下:
       先用
另一个数除以一个数,得第一个余数;

       再用上一次的除数除以第一个余数,得第二个余数;

       又用上一次的除数除以第二个余数,得第三个余数;

这样逐次上一次除数除以前一个余数,直到余数是0为止.那么,最后一个除数就是所求的最大公约数。

        最大公倍数即为两个数的积除以两个数的最小公约数。

       算出在最小公倍数以内我胜利的回合,再用k除以最小公倍数以内我胜利的回合,就可算出k回合以内我赢的次数了。

       如果k%最小公倍数以内我胜利的回合不为0的话,那么还需在一开始用个变量保存余数,在for循坏中找出当i等于余数时,用个变量c保存当前我胜利的次数,最后只需输出k除以最小公倍数以内我胜利的回合加上c即可。

      程序如下:

       

#include<iostream>
#include<cstdio>
#include<cstdlib>
using namespace std;
int a,b,c,d[105],e[105],f,j,l,m,n,p,v,q,k,r;
bool vt(int o,int z)//用函数判断我是否赢了 
{
	if(o==3&&z==1)
	return true;
	else
	if(o==1&&z==2)
	return true;
	else
	if(o==2&&z==3)
	return true;
	else
	return false;
}
int main()
{
	freopen("game.in","r",stdin);
	freopen("game.out","w",stdout);
	cin>>n>>k>>p;
	a=n;
	b=k;
	c=a%b;
	while(c!=0)//辗转相除法 
     {	 
	     a=b;
		 b=c;
     	c=a%b;
	   
     }
     a=n*k/b;
     b=p%a;
     for(int i=1;i<=n;i++)
        cin>>d[i];
     for(int i=1;i<=k;i++)
        cin>>e[i];
     for(int i=1;i<=a;i++)//for循环算出最小公倍数以内我胜利的回合 
     {
     	    f++;
     	    j++;
          if(vt(d[f],e[j]))
            l++;
          if (i==b)//用个变量c保存当前我胜利的次数
            c=l;
          if(f==n)
            f=0;
          if(j==k)
            j=0;
     }
      cout<<l*(p/a)+c<<' ';
     return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值