我无法理解以下问题的解决方案:
爱丽丝和鲍勃正在玩游戏。在这个游戏中,玩家应该同时使用手牌显示0到1000万之间的整数。如果两个球员显示的数字相等,我们就会打成平局。否则,玩家会在一张纸上交替写下数字。
设A是比赛开始时由Alice显示的整数,让B为Bob的整数显示,写下的每个数字必须是| A - B |的乘积。因子,所有因子都是素数,不一定是不同的,属于由整数A和B定义的区间。
爱丽丝总是先玩。
例如,如果A = 2且B = 5,那么只有10个数字(Bob Wins)可以写在论文中,它们是:
8 = 2 x 2 x 2
12 = 2 × 2 × 3
20 = 2 × 2 × 5
18 = 2 × 3 × 3
30 = 2 × 3 × 5
50 = 2 × 5 × 5
27 = 3 × 3 × 3
45 = 3 × 3 × 5
75 = 3 × 5 × 5
125 = 5 × 5 × 5
输入有两个数字A和B,如上所述。
输出有1行,单独包含比赛获胜者的名字,假设两名球员都发挥得最佳。如果匹配,则输出行应单独包含符号“?”。
以下是此问题的解决方案:
#include <stdio.h>
#include <math.h>
#include <string.h>
#define MAX 11234567
int primes[MAX], primeIndex;
inline void sieve(int limit) {
bool sieve[limit];
memset(sieve, 0 , sizeof(sieve));
primeIndex = 0;
primes[primeIndex] = 2;
for (int i = 3; i < limit ; i += 2) {
if(!sieve[i]){
primes[++primeIndex] = i;
for (int j = i + i; j <= limit; j += i) {
sieve[j] = 1;
}
}
}
++primeIndex;
}
inline int mul(int n) {
int ret = 0;
while (n > 0) {
n /= 2;
ret += n;
}
return ret;
}
inline void swap(int *a, int *b){
int aux = *a;
*a = *b;
*b = aux;
}
int main(void) {
int A, B;
scanf("%d %d", &A, &B);
if (A == B) {
puts("?");
return 0;
}
if (A > B) {
swap(&A, &B);
}
sieve(B);
int position_of_largest_prime;
for (position_of_largest_prime = 0; position_of_largest_prime < primeIndex && primes[position_of_largest_prime] < A; ++position_of_largest_prime);
int intervalBA = B - A;
int primeCount = (primeIndex - position_of_largest_prime);
puts(primeCount > 0 && mul(intervalBA + primeCount - 1) == mul(primeCount - 1) + mul(intervalBA) ? "Alice" : "Bob");
return 0;
}
mul(intervalBA + primeCount - 1)== mul(primeCount - 1)+ mul(intervalBA)
我不明白上述情况。 这是一些数论问题吗? 有人可以帮我识别吗?
如答案所指出的那样,缺乏有关描述的信息。 Here是问题的链接,详细说明。
答案 0 :(得分:2)
有一些关于游戏的细节并没有明确解释。例如,情况可能是Alice和Bob在比赛开始时没有选择相同的数字,但是在他们选择的数字之间没有素数。如果A = 14且B = 16,这是一个平局吗?如果是这样,我认为您提供的解决方案在所有情况下都不正确,因为在Bob
的情况下,输出似乎是?
而不是primeCount = 0
。另外,我假设写下最后一个号码的人是赢家,但在游戏说明中没有明确说明。
但是,您的主要问题似乎是涉及的组合。如果我正确理解游戏,那么如果A和B之间有素数,我们需要确定是否有不同产品的数量。 B - A |这些素数是偶数还是奇数。人们可能会问的第一个问题是,“有多少种不同的产品?”计算这些的一个好方法是使用星形和条形方法。你可以阅读更多有关星星和条形here的信息,但在你的示例游戏中,需要选择|B-A| = 3
个素数,我称之为三个星,两个条形,两个之间的分隔线头两个和三个以及三到五之间的分隔线。因此,*|*|*
代表产品2 x 3 x 5
,**|*|
代表产品2 x 2 x 3
,*||**
代表产品2 x 5 x 5
。请注意,条形数量比A和B之间的间隔中的质数数量少一个。因此,作为一个组合问题,我们选择整个序列中的星和条的位置。整个序列的长度为intervalBA + primeCount - 1
,要选择的星级位置数为intervalBA
。
如果我们要计算不同组合的数量,那么我们将计算intervalBA
个对象可以制作多少个intervalBA + primeCount - 1
组合。换句话说,我们会计算intervalBA + primeCount - 1
选择intervalBA
。但是,该数字很容易超过您正在使用的计算机上的整数大小,因此直接计算是不可行的。相反,我们应该找到一种方法来决定该计算的结果是偶数还是奇数,而不直接计算结果。
使用Lucas定理可以确定结果是偶数还是奇数。我将提供一个Wikipedia article关于该定理的链接和一个question on Math stack exchange,其中一条评论讨论了如何应用卢卡斯定理来回答组合是偶数还是奇数的问题。二进制数字表示。
解决方案的mul
函数也可用于确定结果是偶数还是奇数而不直接计算结果。它与卢卡斯定理得到的解决方案略有不同。这不是我以前见过的,但我最终确定mul(n)
计算将n
阶乘除以2的最大幂。使用!
表示阶乘,n
选择k
的基本定义通常为n!/(k!(n-k)!)
。因此,条件mul(intervalBA + primeCount - 1) == mul(primeCount - 1) + mul(intervalBA)
正在检查除以分子的2的最大幂是否等于除以分母的最大幂2,其中n
是intervalBA + primeCount - 1
和{{1}是k
。如果除以分子的2的最大幂等于除以分母的2的最大幂,则intervalBA
选择n
将是奇数并且Alice将获胜。否则,k
选择n
将是偶数,Bob将获胜。
如果代码中的代码能够正确记录它的作用,那么代码就像解决方案中的代码一样容易理解。