大家好我是清墨,今天我们由一道题来复习我们以前学过的内容。
题目描述
大联欢的最后项目是小明和小李的射击比赛。比赛规则是这样的,每次两人同时射击,每个人有 S 枚子弹进行射击,第 1 秒两人同时打出第一枚子弹,以后的 s-1 子弹可以自己根据一定的间隔时间打出,设小明后面的子弹每隔 t1 秒打出一枚子弹,小李后面的子弹每隔 t2 秒打出一枚子弹,如 t1=2 时,则小明子弹打出的时刻分别为 1,4,7,10,13,…,同理可得小李子弹打出的时刻。如果某一时刻两人同时打出子弹,则只能听到一次响声,你知道这两个人的比赛过程中我们共能听到几次枪声吗?
输入格式
输入数据共有三行. 第一行有一个正整数 S,它的范围[1..100000]。
第二行有一个正整数 t1,它的范围[1..10000]。
第三行有一个正整数 t2,它的范围[1..10000]。
输出格式
比赛过程中能听到几次枪声。
样例
输入数据 1
5
2
3
输出数据 1
8
方法一
看到这道题,我们第一时间想的是下标计数打表,用数组?
NO,用STL映射,因为我们数组的范围不够题目的要求。
代码:
#include<bits/stdc++.h>
using namespace std;
int n,t2,t1,S;
int x;
map<int,int>a;
int main(){
cin>>n>>t1>>t2;
for(int i=0;i<n;i++)
{
a[1+(t1+1)*i]=1;
//1+0*(t1+1) 1+1*(t1+1) 1+2*(t1+1)......1+(n-1)(t1+1)
//这就是i从0到n的原因
a[1+(t2+1)*i]=1;
}
cout<<a.size();
return 0;
}
方法二
有些同学豁然开朗想到能用集合来写。
代码:
#include<bits/stdc++.h>
using namespace std;
set<int>x;
int t1,t2,ss;
int main()
{
cin>>ss>>t1>>t2;
for(int i=0;i<=ss-1;i++)
{
x.insert(i*(t1+1));
//其实你加不加一都没有关系的
x.insert(i*(t2+1));
}
cout<<x.size();
return 0;
}
方法三
清墨想到了用公倍数来写。
代码:
#include<bits/stdc++.h>
using namespace std;
//转化成找t1 t2的最小公倍数的倍数个数
//总的枪数2*s-同时的(t1 t2的最小公倍数的倍数个数+第一枪)
//在提前结束那个人的时间段找最小公倍数的个数
int main()
{
int s,t1,t2,gcd,lcm,ans;
cin>>s>>t1>>t2;
t1++; //转化成倍数问题,两枪之间间隔 t1 秒,枪响又是 1 秒,所以,一个周期就是 t1+1 秒
t2++; //两枪之间间隔 t2 秒,枪响又是 1 秒,所以,一个周期就是 t1+1 秒
if(t1>t2) swap(t1,t2); //一般化处理,确保t1<=t2;
//t1<t2,小明的枪声先结束,最后的一声枪响在 (s-1)*t1
//小明抢响时间为 1 1+(t1+1) 1+2*(t1+1) ...... 1+(n-1)*(t1+1)
//平移坐标轴 枪响时间为 0,t1,2*t1,3*t1,.....,(s-1)*t1
//小李的枪响时间为 1 1+(t2+1) 1+2*(t2+1) 1+(n-1)*(t2+1)
// 两个人枪声重叠的时间为最小公倍数的倍数时间点
gcd=__gcd(t1,t2); //先求最大公约数
lcm=t1*t2/gcd; // 公式法求最小公倍数
ans = 2*s - (s-1)*t1/lcm -1 ; //有多少个公倍数的倍数,就扣减多少 ,最后减 1 是因为还有 0 时间点重叠的那一枪
cout<<ans;
return 0;
}