USACO 2019 December Contest, Silver MooBuzz
MooBuzz题解
题目描述
Farmer John 的奶牛们最近成为了一个简单的数字游戏“FizzBuzz”的狂热玩家。这个游戏的规则很简单:奶牛们站成一圈,依次从一开始报数,每头奶牛在轮到她的时候报一个数。如果一头奶牛将要报的数字是 3 的倍数,她应当报“Fizz”来代替这个数。如果一头奶牛将要报的数字是 5 的倍数,她应当报“Buzz”来代替这个数。如果一头奶牛将要报的数字是 15 的倍数,她应当报“FizzBuzz”来代替这个数。于是这个游戏的开始部分的记录为:
1, 2, Fizz, 4, Buzz, Fizz, 7, 8, Fizz, Buzz, 11, Fizz, 13, 14, FizzBuzz, 16
由于词汇的匮乏,奶牛们玩的 FizzBuzz 中用“Moo”代替了 Fizz、Buzz、FizzBuzz。于是奶牛版的游戏的开始部分的记录为:
1, 2, Moo, 4, Moo, Moo, 7, 8, Moo, Moo, 11, Moo, 13, 14, Moo, 16
给定 N(1≤N≤109),请求出这个游戏中第 N 个被报的数。
测试点性质:
测试点 2-5 满足 N≤106。
输入格式(文件名:moobuzz.in)
输入包含一个整数 N。
输出格式(文件名:moobuzz.out):
输出游戏中被报出的第 N 个数。
输入样例:
4
输出样例:
7
第 4 个被报的数是 7。前 4 个被报的数是 1、2、4、7,因为我们在奶牛说“Moo”时就会跳过数字。
供题:Brian Dean
解题思路
在这里我们采用\(n\)来表示游戏中报的数字数,也就是第N个被报的数,也就是输出的值;用\(k\)来表示输入的值。
采用容斥原理可以得到
\(k=n-\left \lfloor n/3 \right \rfloor-\left \lfloor n/5 \right \rfloor+\left \lfloor n/15 \right \rfloor\)
可以改写为
\(k=n-(n/3-\alpha)-(n/5-\beta)-(n/15-\gamma)\)
其中,\(\alpha,\beta,\gamma \in [0,1)\)
上式可以改写成:\(n=(k*15-15*\alpha-15*\beta+15*\gamma)\)
采用放缩法,令\(\alpha=\beta=1,\gamma=0\) 得
\(n_{lowBownd}=(k*15-30)/8 \approx(k/8)*15-4\)
然后从\(n_{lowBownd}\)向上搜索答案。
代码
`
long long calc(long long k, long long n)
{ return k == (n - n / 3 - n / 5 + n / 15);
}
int main()
{
ofstream fout("moobuzz.out");
ifstream fin("moobuzz.in");
long long k;
fin >> k;
int n;
int minBound = (k / 8) * 15 - 4;
for (n = minBound;; n++)
{
if (calc(k, n))
{
break;
}
}
fout << n;
fin.close();
fout.close();
return 0;
}
`