3

質問はタイトルにあります。ここで、自己生産という用語をより明確にします。自己積とは、数とその桁の積を意味します。例:

自己積(1234) = 1234*1*2*3*4 = 29616.

私は2つの方法を試しました。

強引な

誰のアイデアも、1 と N (範囲の上限) の間のすべての組み合わせをチェックすることです。数値の自己積が範囲内にあるかどうかを確認します。これは比較的低い数値には理想的ですが、範囲が 10^20 と大きくなる可能性があることを念頭に置くと、結果が出力されるまでに時間がかかるため、問題になりつつあります。

因数分解

別のアイデアは、範囲内の数値を因数分解することです。範囲が 60 000 ~ 70 000 の場合、62 688 を確認すると、62 688 は 2*2*2*2*2*3*653 となります。653 を数字にすることはできないことがわかったので、元の数字にする必要があります。次に、正しい答えを得るために 62 688 のすべての因数を組み合わせる必要があり、62 688 = 2612 * 2 * 6 * 1 * 2 であるため、これは 2612 の自己積であることが出力されるはずです。

どちらの状況でも、すべての組み合わせをチェックするという大きな問題に直面しています。

PS私は、数値がn桁の場合、それが何らかの数値の自己積である場合、その数値は少なくともn / 2桁でn以下になることを発見しました。これにより、チェックする必要がある数値のリストが少し小さくなりますが、問題は解決しません。

4

2 に答える 2

1

ネーミング:

sp(x) = Self-Product(x) = y
Range = a to b

ノート:

カウントが必要なだけだと思いますが、これを拡張して実際にすべての数値を出力することは難しくありません。

基本的な考え方 -xを特定の数のプレフィックスと特定の桁数を持つように分割し、一部の桁数 + プレフィックスが範囲内にあるかどうかを完全に (可能性の数を追加し、計算しやすく)、部分的に (より長いプレフィックスをチェックする) またはまったくしない (移動する)。

then = 0xであるため、0 を含む数値は許可されないことに注意してください。y

このアルゴリズムにはいくつかの非効率性があるかもしれませんが、適切な出発点を提供するはずです。改善点の 1 つは、バイナリ検索のようなプロセスを実行できるようにすることです。ここにはある程度の冗長性があるため、最小/最大を常に再計算するわけではありません。

表記法:
min(c,d) - c 桁と接頭辞 d の最小値 (接頭辞がmin(c,)ないことを意味します)
max(c,d)- c 桁と接頭辞 d の最大値- から~の
range(c,d)範囲min(c,d)max(c,d)

注意してmin(x,) = min(x,1) < min(x,2) < min(x,3) < ...ください
max(x,) = max(x,9) > max(x,8) > max(x,7) > ...

min(c,d..e)
- c 桁と d から e までの任意の接頭辞(min(c,d)との間min(c,e))を含む最小値のセット - c 桁と d から e までの
max(c,d..e)任意の接頭辞を含む最大値のセット(と
の間)max(c,d)max(c,e)

例によるアルゴリズム:

Range=100~200の例で説明します。

// check 1 digit
min(1,): x = 1, y = 1*1 = 1 < 100
max(1,): x = 9, y = 9*9 = 81 < 100
  // not in range, nothing to do

// check 2 digits
min(2,): x = 11, y = 11*1*1 = 11 < 100
max(2,): x = 99, y = 99*9*9 = 8019 > 200
  // partially in range, check longer prefix
  min(2,1): x = 11, y = 11*1*1 = 11 < 100
  max(2,1): x = 19, y = 19*1*9 = 171 > 100
    // partially in range, check longer prefix
    sp(11..16) <= sp(16) = 96 < 100
    sp(17) = 119 // in range - increment count
    sp(18) = 144 // in range - increment count
    sp(19) = 171 // in range - increment count
  min(2,2): x = 21, y = 21*2*1 = 42 < 100
  max(2,2): x = 29, y = 29*2*9 = 522 > 200
    // partially in range, check longer prefix
    // others outside of range, omitted for brevity
    sp(23) = 138 // in range - increment count
    sp(24) = 192 // in range - increment count
  min(2,3): x = 31, y = 31*3*1 = 93 < 100
  max(2,3): x = 39, y = 39*3*9 = 1053 > 200
    // partially in range, check longer prefix
    // others outside of range, omitted for brevity
    sp(32) = 192 // in range - increment count
  min(2,4): x = 41, y = 41*4*1 = 164 < 200
  max(2,4): x = 49, y = 49*4*9 = 1764 > 200
    // partially in range, check longer prefix
    // others outside of range, omitted for brevity
    sp(41) = 164 // in range - increment count
  min(2,5): x = 51, y = 51*5*1 = 255 > 200
    // not in range, nothing to do
  // no need to process (2,6..9), since these are all > min(2,5) > 200

// check 3 digits
min(3,): x = 111, y = 111*1*1*1 = 111 < 200
max(3,): x = 999, y = 999*9*9*9 = 728271 > 200
  // partially in range, check longer prefix
  min(3,1): x = 111, y = 111*1*1*1 = 111 < 200
  max(3,1): x = 199, y = 199*1*9*9 = 16119 > 200
    // partially in range, check longer prefix
    min(3,11): x = 111, y = 111*1*1*1 = 111 < 200
    max(3,11): x = 119, y = 119*1*1*9 = 1071 > 200
      // partially in range, check longer prefix
      // others outside of range, omitted for brevity
      sp(111) = 111 // in range - increment count
    min(3,12): x = 121, y = 121*1*2*1 = 242 > 200
      // not in range, nothing to do
    // no need to process (3,13..19), since these are all > min(3,12) > 200
  min(3,2): x = 211, y = 211*2*1*1 = 411 > 200
    // not in range, nothing to do
  // no need to process (3,3..9), since these are all > min(3,2) > 200

// check 4 digits
min(4,): x = 1111, y = 1111*1*1*1 = 1111 > 200
  // not in range, nothing to do
// no need to check more digits, since min(n,) > min(n-1,) and min(4,) > 200

したがって、合計数は 8 個の自己積であり、100 から 200 の範囲になります。

範囲の開始をチェックすることもあれば、終了をチェックすることもあります。これは、その特定のケースでどの条件が重要かを示すためのものです。

例として、範囲が 1 ~ 200 の場合、接頭辞 1 の付いた 2 桁の数字の範囲は上記のように [11,171] となり、1 <= 11 <= 171 <= 200 となるため、以下を含めることができます。プレフィックス 1 が付いたすべての 2 桁の数字で、そのうちの 9 つがあります。

実装:

基本的な実装を備えた小さな Java プログラムを作成しました。60000 から 100000000000 の場合は 1 秒もかからず、より大きな数の場合 (この範囲であっても)、実装のために算術オーバーフローが発生するため、かかる時間は実際には信頼できません (ただし、そうであることを願っています)。 (この範囲では)長くかかるだけで、短くはなりません)。

final static long[] tenPowers = {1, 10, 100, 1000, 10000, 100000, 1000000,
  10000000, 100000000, 1000000000, 10000000000l, 100000000000l,
  1000000000000l, 10000000000000l, 100000000000000l, 1000000000000000l,
  10000000000000000l, 100000000000000000l, 1000000000000000000l};

public static void main(String args[]) throws InterruptedException
{
  System.out.println("Count = "+selfProductCountRange(60000, 100000000000l));
}

static long selfProductCountRange(long s, long f)
{
  start = s;
  finish = f;
  long count = 0;
  for (len = 1; ; len++)
  {
     long temp = selfProductCount(0, 0);
     if (temp == -1)
        break;
     count += temp;
  }
  return count;
}

static long selfProduct(long num)
{
  // pretend 0s are 1s for simplicity in the rest of the code
  long selfProduct = num;
  while (num > 0)
  {
     selfProduct *= Math.max(num % 10, 1);
     num /= 10;
  }
  return selfProduct;
}

static long start, finish;
static int len;

static long selfProductCount(long prefix, int prefixLen)
{
  long max = selfProduct((prefix+1) * tenPowers[len - prefixLen] - 1);
  // overflow hack
  if (max < 0)
     max = finish+1;
  if (max < start)
     return 0;
  long min;
  if (prefixLen != 0)
     min = selfProduct(prefix * tenPowers[len - prefixLen]);
  else
     min = selfProduct(tenPowers[len-1]);
  if (min > finish)
     return -1;
  if (max <= finish && min >= start)
     return getPossibilities(prefixLen);
  long val = 0;
  for (int i = 1; i < 10; i++)
  {
     long temp = selfProductCount(prefix*10+i, prefixLen+1);
     if (temp == -1)
        break;
     val += temp;
  }
  return val;
}

static long getPossibilities(int prefixLen)
{
  return (long)Math.pow(9, len-prefixLen);
}
于 2013-03-29T17:47:16.080 に答える
0

digitsしたがって、積は と によって形成されると言いますnumber

digits() を列挙し、すべての順列 (数値を形成する) をチェックして、範囲内にあるかどうかを確認します。

明らかな剪定は、数字と最小順列の積が上限よりも大きい場合に返されます。

32ビット整数には十分速いと思います。

于 2013-03-29T07:53:49.353 に答える