自然数除数的颜色

Colors of natural number divisors

本文关键字:颜色 自然数      更新时间:2023-10-16

我对一个名叫多雷尔的人有这个学校问题,他的生日收到了一个数字n

他想用一种颜色给从1到n的所有自然数着色,这样他自己对一个数的所有除数都与这个数字具有相同的颜色。

该问题要求找出可以使用的最大颜色数。

例如,通过n = 5,您有:

  • 1 红
  • 2 绿色
  • 3
  • 蓝色
  • 4 绿色
  • 5
  • 黄色

所以在这个例子中,我们需要 4 种颜色。

练习可以在这里找到,但它是罗马尼亚语。

质数出现问题,所以我在想一种方法来计算从1n有多少个素数,然后将其添加到所需的颜色数量中。

我尝试了复杂的解决方案,如实现米勒-拉宾素数测试和埃拉托色尼,但对于网站上的自动测试,它仍然太慢了。

我是否错过了什么,或者解决这个问题的唯一方法是找到 1 到 n 之间的每个素数?

我按照维基百科的例子实现埃拉托色尼:

/* https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes#Overview */
void prime(uint n) {
if (n < 1) return;
/* Create a list of consecutive integers from 2 through n: (2, 3, 4, ..., n). */
uint size = n - 1;
uint *list = (uint *)malloc(sizeof(uint) * size);
for (uint i = 0; i < size; i++) {
list[i] = i + 2;
}
/* Initially, let p equal 2, the smallest prime number. */
uint p = 2;
uint c = 1;
while (c < n) {
/*
* Enumerate the multiples of p by counting in increments of p from 2p to n,
* and mark them in the list (these will be 2p, 3p, 4p, ...; the p itself should not be marked).
*/
for (uint i = c; i < size; i++) {
if (list[i] % p == 0) {
list[i] = 0;
}
}
/*
* Find the first number greater than p in the list that is not marked.
* If there was no such number, stop.
* Otherwise, let p now equal this new number (which is the next prime).
*/
while (c < n) {
if (list[c] > p) {
p = list[c++];
break;
}
c++;
}
}
/* the numbers remaining not marked in the list are all the primes below n */
for (uint i = 0; i < size; i++) {
if (list[i] != 0) {
printf("%d ", list[i]);
}
}
printf("nn");
}

问题是你一遍又一遍地对单个数字使用算法。如果你想检查很多数字,很多工作可以重用。

我会做这样的事情:

bool * calculatePrimeArray(int n) 
{
bool * ret = malloc(n*sizeof(*ret)+1);
for(int i=0; i<n*sizeof(*ret)+1; i++) ret[i]=true;
ret[0]=ret[1]=false;
int cur = 2;
while(cur < n/2+1) {
if(ret[cur])
for(int i=cur*2; i<n; i+=cur) ret[i] = 0;
cur++;
}
return ret;
}

这将返回一个布尔数组 ret,其中 ret[i] 指示 i 是否是素数。

如果要使其对缓存更友好,可以使用位字段而不是布尔变量。

使用@Bromax答案,我让它工作,它在网站上的所有测试中都得了 100 分:

#include <cstdlib>
#include <iostream>
#include <cmath>
#define PRIME 0
#define NOT_PRIME 1
bool *primes(int n) {
bool *ret = (bool *)calloc(n + 1, sizeof(bool));
ret[0] = ret[1] = NOT_PRIME;
uint cur = 2;
while (cur <= sqrt(n)) {
if (ret[cur] == PRIME) {
for (uint i = cur * cur; i <= n; i += cur) {
ret[i] = NOT_PRIME;
}
}
cur++;
}
return ret;
}
int main() {
FILE *input = NULL;
FILE *output = NULL;
input = fopen("primcolor.in", "r");
uint n;
fscanf(input, "%d", &n);
if (n < 1 || n > 50000000) {
fclose(input);
return 1;
}
output = fopen("primcolor.out", "w");
if (n <= 3) {
fprintf(output, "%dn", n);
fclose(input);
fclose(output);
return 0;
}
uint colors = 2;
bool *a = primes(n);
for (uint i = (n / 2 + 1); i <= n; i++) {
if (a[i] == PRIME) {
colors++;
}
}
fprintf(output, "%dn", colors);
fclose(input);
fclose(output);
return 0;
}

正如建议的那样,最快的方法是创建一个数组,用作从0n的所有数字的缓存