题目描述
今天是星期天,小楠楠来找你玩“石头、剪刀、布游戏”。你正在学习信息学,所以想了一种需要编程来玩的“石头、剪刀、布游戏”。首先,用数字1,2,3分别表示出石头、剪刀、布。其次,你确定自己前N次“石头、剪刀、布”的出拳方法,下面N次再次同样出拳,…,周而复始;也要求楠楠确定他前M次的出拳方法,然后周而复始。问第K次后,你赢了几次?
例如:N=4,你的前4次出拳方式是“石头、剪刀、布、布”,用数字表示即:”1 2 3 3”。M=5,楠楠前5次出拳方式是“剪刀、石头、石头、布、布” ,用数字表示即:”2 1 1 3 3”。K=10时,情况如下表:
你共赢了5次。
输入
第一行3个整数N,M,K。分别表示你出拳方式的周期长度、楠楠出拳方式的周期长度和总共玩的次数。
第二行有N个整数,每个整数为1、2、3其中之一。
第三行有M个整数,每个整数为1、2、3其中之一。
提示
8个数据: N,M 的范围是[1..100],K的范围是[1…100,000]。
2个数据: N,M的范围是[1..100],K的范围是[1…1,000,000,000]
本题的数据量很大,主要考察了对时间复杂度的处理,不能进行暴力从0到k遍历下去,时间复杂度会太大,因为N,M是有周期的,我们只需要找到他们之间的最小公倍数,这就是他们的一个最小正周期,每一次经过这一个周期都会有一个固定的值,到最后让结果先加上几个正周期的结果,然后让总次数减去周期*周期个数,最后再单独算剩下的情况,加上就行了,答案就是最小公倍数比较次数乘以k/最小公倍数+k%最小公倍数比较次数
#include <iostream>
#include <algorithm>
using namespace std;
int main() {
ios::sync_with_stdio(0);//可以抵消cin和scanf之间效率的差别
cin.tie(0);
cout.tie(0);
int a[101] = { 0 };
int b[101] = { 0 };
long long int m, n, o, count = 0, count1 = 0;
cin >> m >> n >> o;
for (int i = 0; i < m; i++) {
cin >> a[i];
}
for (int i = 0; i < n; i++) {
cin >> b[i];
}
int temp = max(m, n);//求最小公倍数,即最小正周期
for (int i = temp;; i++) {
if (i % n == 0 && i % m == 0) {
temp = i;
break;
}
}
int j = 0, k = 0;
for (int i = 0; i < o % temp; i++) {//多出来的部分
if (a[j] == 1 && b[k] == 2 || a[j] == 2 && b[k] == 3 || a[j] == 3 && b[k] == 1) {
count1++;
}
j++;
k++;
if (j == m) {
j = 0;
}
if (k == n) {
k = 0;
}
}
for (int i = 0; i < temp; i++) {//一个周期内获胜次数
if (a[j] == 1 && b[k] == 2 || a[j] == 2 && b[k] == 3 || a[j] == 3 && b[k] == 1) {
count++;
}
j++;
k++;
if (j == m) {
j = 0;
}
if (k == n) {
k = 0;
}
}
cout << count * (o / temp) + count1;
return 0;
}
这是暴力遍历和优化后时间复杂度的差别