Vanya and his friend Vova play a computer game where they need to destroy n monsters to pass a level. Vanya's character performs attack with frequency x hits per second and Vova's character performs attack with frequency y hits per second. Each character spends fixed time to raise a weapon and then he hits (the time to raise the weapon is 1 / x seconds for the first character and 1 / y seconds for the second one). The i-th monster dies after he receives ai hits.
Vanya and Vova wonder who makes the last hit on each monster. If Vanya and Vova make the last hit at the same time, we assume that both of them have made the last hit.
The first line contains three integers n,x,y (1 ≤ n ≤ 105, 1 ≤ x, y ≤ 106) — the number of monsters, the frequency of Vanya's and Vova's attack, correspondingly.
Next n lines contain integers ai (1 ≤ ai ≤ 109) — the number of hits needed do destroy the i-th monster.
Print n lines. In the i-th line print word "Vanya", if the last hit on the i-th monster was performed by Vanya, "Vova", if Vova performed the last hit, or "Both", if both boys performed it at the same time.
4 3 2 1 2 3 4
Vanya Vova Vanya Both
2 1 1 1 2
Both Both
In the first sample Vanya makes the first hit at time 1 / 3, Vova makes the second hit at time 1 / 2, Vanya makes the third hit at time 2 / 3, and both boys make the fourth and fifth hit simultaneously at the time 1.
In the second sample Vanya and Vova make the first and second hit simultaneously at time 1.
题意:就是输入三个数n,x,y, x 代表着Vanya一秒中能打x拳,y代表着 Vova一秒中能打y拳, n代表下面的测试数据有多少组,下面给你n组测试数据,每组测试数据代表着这个怪打多少下就死了,输出是谁打死的;
思路一:x 代表着 Vanya 一秒中能打x拳,y代表着Vova 一秒中能打y拳,那么1/x 秒Vanya 能打一拳,1/y秒 Vova 能打一拳,同时扩大x*y倍,不就是,Vanya y 秒能打一拳,Vova x 秒能打一拳,他们两个从0开始计时,到下次在同一时刻各打出一拳,那么这一时刻,一定是x和y的公倍数,那么最小的也就是最小公倍数了,最小公倍数为时间周期,那么在这个时间周期中能打这个怪多少拳呢?我开始以为是x+y拳,其实不是,最小的拳数周期为 x/gcd(x,y) + y/gcd(x.y) ;举个例子 在一定时间中,Vanva 能打2拳,Vova 能打 6 拳,那么当Vanva能打1拳时,Vova能打3拳,所以他们的拳数最小周期为4而不是8;
代码:
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define Max 2000010
long long book[Max]; // 标记一个拳数周期
long long gcd(long long a,long long b)
{
if(b==0)
return a;
else
{
long long tt = gcd(b,a%b);
return tt;
}
}
int main()
{
long long i,j,k1,k2,m,n,pp,k;
while(~scanf("%lld%lld%lld",&k,&m,&n))
{
long long tt = m*n;
long long g = gcd(m,n); //最大公约数;
long long kk = m/g+n/g; //达到最大公约数之前会出现打多少拳,一个周期;
tt=tt/g; // tt 为最小公倍数;(只有达到公倍数时,a人和b人才能在同一时刻各打出一拳);
int f = 0; // 只有从0时刻找到第一个同时打出一拳的时刻,这是一个时间周期,所以就找最小公倍数;、
//而在这个时间周期中,你能打出的拳数就是m:n为最简时,m+n拳,
// 举个例子就是当a打出 2拳时,b能打 6拳,那么当a 打出1拳时,b就能打3拳,这时也就是最简了,这就是拳数的周期;
if(n>m)
{
f = 1;
k1 = m;
k2 = n;
}
else
{
k1 = n;
k2 = m;
}
i = k1; // k1为m,n中小的那个;k2为较大的那个;
long long num1 = 1, num2 = 1,num = 1; //在i秒时,num1 记录k1 的打了多少拳,num2 为k2打了多少拳,num为总拳数
while(i<=tt)
{
if(i%k1==0)
{
if(k2*num2<i)
i = k2*num2; // 挺重要的;
else
{
num1++;
book[num] = k1;
num++;
i+=k1;
}
}
else if(i%k2==0)
{
if(k1*num1<i)
i = k1*num1; //挺重要;
else
{
num2++;
book[num] = k2;
num++;
if(i+k2 > num1*k1) //最重要 若 x=2,y=6;若不加这一步,就把i=4给隔过去了;
{ // 比赛中我就是没加这一步一直不过;
i = num1*k1;
}
else i+=k2;
}
}
}
for(j=0;j<k;j++)
{
scanf("%lld",&pp);
pp = pp%kk;
if(pp==0||pp==kk-1)
{
printf("Both\n");
continue;
}
if(f)
{
if(book[pp]==k1)
printf("Vova\n");
else printf("Vanya\n");
}
else
{
if(book[pp]==k1)
printf("Vanya\n");
else printf("Vova\n");
}
}
}
return 0;
}
思路二:
就是用二分的思想写,一直二分时间,定义一个很大的时间了 l = 0, r = 很大的时间
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
long long tt = 1;
void init()
{
tt<<=50;
//printf("tt==%lld\n",tt);
}
int main()
{ init();
long long i,j,n,x,y,kk;
while(~scanf("%lld%lld%lld",&n,&x,&y))
{
for(i=0;i<n;i++)
{
scanf("%lld",&kk);
long long ans,mid, l = 0,r = tt;
while(l<=r)
{
mid = (l+r)/2;
if(mid/x+mid/y>=kk) // 这个二分法这用的挺好>=号,把mid 赋值给ans;
{
ans = mid; // 这个等于号的作用就是,找到恰好 打了kk下的时间,
r = mid -1; //时间少一刻钟也就不满足了,所以上一刻钟就是恰好满足,也就是一定能对x取余等于0或者对y取余等于0;
} // 一定要学会这样的二分法;
else l = mid + 1;
}
if(ans%x==0&&ans%y==0)
printf("Both\n");
else if(ans%x==0)
printf("Vova\n");
else if(ans%y==0)
printf("Vanya\n");
}
}
return 0;
}