简体   繁体   English

算法,在给定的最小值和最大值之间找到“数字不除以平方数”

[英]Algorithm, finding “number not divided by square numbers” between given min and max value

Problem 问题

There is a minimum value min and maximum value max, find all the numbers which not divided by "square numbers" between min and max. 有最小值min和最大值max,请找到所有在min和max之间未除以“平方数”的数字。 (1<=min<=1trilion, max-min<=1,000,000) (1 <= min <= 1三角级,max-min <= 1,000,000)

Example

min is 1, max is 10. 最小为1,最大为10。

The answer is 7 from 1,2,3,5,6,7,10 because 4,8 is divided by square number 2^2=4. 答案是1,2,3,5,6,7,10中的7,因为4,8除以平方数2 ^ 2 = 4。


My approach. 我的方法。

  1. All numbers divided by square number are also divided by square prime number. 所有数字除以平方数也将除以平方质数。

  2. Using seive of eratosthenes, computed all the square prime numbers smaller than sqrt(max) 使用seatosthenes的seive,计算所有小于sqrt(max)的平方素数

  3. Finding all numbers divided by above suqare prime numbers. 查找所有数字除以上述suqare质数。

But I got "time limit" or "Wrong" from that site. 但是我从那个站点得到“时间限制”或“错误”。 How can I prove? 我该如何证明? Below is code. 下面是代码。

void Eratos()
{
    for (ll i = 2; i <= primeMax; i++) num[i] = i;

    for (ll i = 2; i <= 100; i++) {
        for (ll j = 2; j <= primeMax; j++) {
            if (num[j] == -1) continue;
            else if (num[j] > i && num[j] % i == 0) num[j] = -1;
        }
    }

    for (ll i = 2, j = 0; i <= primeMax; i++) if (num[i] != -1) {
        prime[j] = num[i]*num[i];
        j++;
    }
}

You are checking check all numbers in range (nr=max-min) against all primes (np), so complexity is O(nr*np) . 您正在检查是否检查所有范围内(nr = max-min)的所有质数(np)的数字,因此复杂度为O(nr*np)

But instead you can make list of prime squares and use Eratosthenes sieve approach again over min..max range, marking squareful numbers. 但是,您可以列出素数平方并在最小..最大范围内再次使用Eratosthenes筛分方法,标记出平方数。 So code will make about 因此,代码将使

Sum (nr / (sq[0]) + nr / (sq[1]) +...nr / (sq[np-1])

steps with complexity (perhaps) about O(np + nr) (可能)关于O(np + nr)复杂步骤

For example, range is 50...80. 例如,范围是50 ... 80。 Prime square list is 4,9,25,49. 总理广场名单是4,9,25,49。 Make boolean or bit array with 31 entries. 用31个条目组成布尔或位数组。 First run marks entries 52,56,60..80. 第一次运行标记条目52,56,60..80。 Second run: 54, 63, 72; 第二轮:54、63、72; third run marks 50,75, and fourth marks nothing. 第三轮为50,75,第四轮为零。 Now unmarked entries 51,53,55..79 is what you need. 现在,您需要的是未标记的条目51,53,55..79。

The first entry in range, divisible by some square psq is 范围中的第一个条目(可被某个平方psq整除)是

((min + psq - 1) div psq) * psq

Delphi code gives result 607923 in 0.1 second Delphi代码在0.1秒内给出结果607923

function CountSquareless(AMin, AMax: Int64): Integer;

var
  PrSqList: TList<Int64>;

procedure MakePrimeList; //Eratosphenes sieve
var
  num: array of Byte;
  i, j: Integer;
begin
  SetLength(num, 1000001);
  PrSqList := TList<Int64>.Create;
  for i := 2 to 1000000 div 2 do
    for j := 2 to (1000000 div i) do
       num[i * j] := 1;
  for i := 2 to 1000000 do
    if num[i] = 0 then
       PrSqList.Add(Int64(i) * i);
end;

var
  num: array of Byte;
  i, nr: Integer;
  psq, first: Int64;
begin
  nr := AMax - AMin;
  SetLength(num, nr + 1);
  MakePrimeList;

  for psq in PrSqList do begin
    first := ((AMin + psq - 1) div psq) * psq;
    while first < AMax do begin //Eratosphenes-like sieve uses prime squares
      num[first - AMin] := 1;
      first := first + psq;
    end;
  end;

  Result := 0;
  for i := 0 to nr - 1 do
    if num[i] = 0 then
      Result := Result + 1;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  Memo1.Lines.Add(IntToStr(CountSquareless(1000000000000 - 1000000, 1000000000000)));

c++ code for sieve 筛子的C ++代码

using namespace std;

typedef long long ll;
const int primeMax = 1000000;
int num[primeMax + 1];
ll prime[100000];
int primecnt = 0;

void Eratos()
{
    for (int i = 2; i <= primeMax; i++) num[i] = i;

    for (int i = 2; i <= primeMax; i++) {
        for (int j = 2; j <= primeMax / i ; j++) {
             num[i * j] = -1;
        }
    }

    for (int i = 2; i <= primeMax; i++)
        if (num[i] != -1) {
          prime[primecnt++] = (ll)num[i] * num[i];
      }
    cout << "last prime squared " << prime[primecnt-1] << " number " << primecnt;
 }

Given that the problem statement asks you to "find all the numbers which not divided" (sic), the fact that you only have one printf and it's not inside a loop of some sort, seems to indicate your solution is more on the "wrong" side of the ledger rather than the "time limit" side. 鉴于问题陈述要求您“查找所有未除的数字”(原文如此),您只有一个 printf且不在某种循环中的事实似乎表明您的解决方案更多是“错误的”而不是“时间限制”端。

I'd suggest fixing that before you worry about speeding it up. 我建议您修复此问题,然后再担心加快速度。 You can't get any less optimised than "wrong" :-) 您无法获得比“错误” 更小的优化:-)


The first thing you should have done is to see what output you got from the input given in the test case - you would have immediately seen that speed is not the issue here: 您应该做的第一件事是查看从测试用例中给出的输入中获得了什么输出-您将立即看到速度不是这里的问题:

pax> echo 1 10 | ./testprog
7

Now my eyes might be getting a bit old nowadays but even I can see there's a difference between 7 and 1,2,3,5,6,7,10 . 现在我的眼睛现在可能变老了,但即使也可以看到71,2,3,5,6,7,10之间存在区别。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM