给定范围内存在多少个PR编号? [英] How many PR numbers exist in a given range?

查看:83
本文介绍了给定范围内存在多少个PR编号?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这不是作业问题。我对这个问题很好奇。我的方法是简单的蛮力:-)

It is not a homework problem. I am just curious about this problem. And my approach is simple brute-force :-)

我的蛮力 C ++ 代码:

int main()
{
    ll l,r;
    cin>>l>>r;

    ll f=0;
    ll i=l;

    while(i<=r)
    {
        ll j=0;
        string s;
        ll c=0;
        s=to_string(i);

        // cout<<s<<" ";

        ll x=s.length();

        if(x==1)
        {
            c=0;
        }
        else 
        {
            j=0;
            //whil
            while(j<=x-2)
            {
                string b,g;

                b="1";
                g="1";

                b=s[j];
                g=s[j+1];

                ll k1,k2;

                k1=stoi(b);
                k2=stoi(g);

                if(__gcd(k1,k2)==1)
                {
                    c=1;
                    break;
                }

                j++;
            }
        }

        ll d=0;
        j=0;
        while(j<=x-1)
        {
            if( s[j]=='2' || s[j]=='3' || s[j]=='5' || s[j]=='7')
            {
                string b;
                b="1";
                b=s[j];
                ll k1=stoi(b);
                if(i%k1==0)
                {
                    //d=0;
                }
                else
                {
                    d=1;
                    break;
                }
            }
            j++;
        }
        if(c==1 || d==1)
        {
            // cout<<"NO";
        }
        else
        {
            f++;
            // cout<<"PR";
        }
        // cout<<"\n";

        i++;
    }

    cout<<f;

    return 0;
}




您将得到2个整数'L'和'R'。您需要查找范围从 L到 R(包括两端)的所有PR号的计数。 PR号是满足以下属性的数字:

You are given 2 integers 'L' and 'R' . You are required to find the count of all the PR numbers in the range 'L' to 'R' inclusively. PR number are the numbers which satisfy following properties:


  1. 没有一对相邻的数字是互质的,即PR中的相邻数字数字不会互为质数。

  1. No pair of adjacent digits are co-prime i.e. adjacent digits in a PR number will not be co-prime to each other.

PR数字可被出现在PR数字中的所有一位数字质数整除。

PR number is divisible by all the single digit prime numbers which occur as a digit in the PR number.

注意:如果gcd(a,b),则两个数字'a'和'b'是互质的= 1。

Note: Two numbers 'a' and 'b' are co-prime, if gcd(a,b)=1.

此外,gcd(0,a)= a;

Also, gcd(0,a)=a;

示例:

输入:[2,5]。

输出: 4。

Example:
Input: [2,5].
Output: '4'.

(注意: 1不是素数-数字,尽管它很常见)

(Note: '1' is not a prime-number, though its very common)

(所有整数: 2, 3, 4, 5)都满足PR数字的条件: -)

(All the integers: '2','3','4','5') satisfy the condition of PR numbers :-)

约束在'L','R'上: 1< ; = L,R< = 10 ^ 18

Constraints on 'L','R': 1 <= L, R <= 10^18

最有效的算法是什么?

推荐答案

我们需要一个表,其中w e可以查找与前缀匹配以构造有效数字的后缀数。给定前缀

We need a table where we can look up the count of suffixes that would match a prefix to construct valid numbers. Given a prefix's

right digit
prime combination
mod combination

以及后缀长度,我们希望可以搜索的后缀数:

and a suffix length, we'd like the count of suffixes that have searchable:

left digit
length
prime combination
mod combination

我开始使用Python进行编码,然后切换到JavaScript以提供摘要。代码中的注释描述了每个查找表。其中有一些可以加快枚举速度。有一些前缀后缀计算示例,以说明如何使用该表构建任意上限,尽管至少有一些可能在制表过程中进行了所有前缀构建和聚合。

I started coding in Python, then switched to JavaScript to be able to offer a snippet. Comments in the code describe each lookup table. There are a few of them to allow for faster enumeration. There are samples of prefix-suffix calculations to illustrate how one can build an arbitrary upper-bound using the table, although at least some, maybe all of the prefix construction and aggregation could be made during the tabulation.

function gcd(a,b){
  if (!b)
    return a
  else
    return gcd(b, a % b)
}

// (Started writing in Python,
// then switched to JavaScript...
// 'xrange(4)' -> [0, 1, 2, 3]
// 'xrange(2, 4)' -> [2, 3]
function xrange(){
  let l = 0
  let r = arguments[1] || arguments[0]
  if (arguments.length > 1)
    l = arguments[0]
  return new Array(r - l).fill(0).map((_, i) => i + l)
}

// A lookup table and its reverse,
// mapping each of the 210 mod combinations,
// [n % 2, n % 3, n % 5, n % 7], to a key
// from 0 to 209.
// 'mod_combs[0]' -> [0, 0, 0, 0]
// 'mod_combs[209]' -> [1, 2, 4, 6]
// 'mod_keys[[0,0,0,0]]' -> 0
// 'mod_keys[[1,2,4,6]]' -> 209
let mod_combs = {}
let mod_keys = {}
let mod_key_count = 0
for (let m2 of xrange(2)){
  for (let m3 of xrange(3)){
    for (let m5 of xrange(5)){
      for (let m7 of xrange(7)){
        mod_keys[[m2, m3, m5, m7]] = mod_key_count
        mod_combs[mod_key_count] = [m2, m3, m5, m7]
        mod_key_count += 1
      }
    }
  }
}

// The main lookup table built using the
// dynamic program
// [mod_key 210][l_digit 10][suffix length 20][prime_comb 16]
let table = new Array(210)
for (let mk of xrange(210)){
  table[mk] = new Array(10)
  for (let l_digit of xrange(10)){
    table[mk][l_digit] = new Array(20)
    for (let sl of xrange(20)){
      table[mk][l_digit][sl] = new Array(16).fill(0)
    }
  }
}

// We build prime combinations from 0 (no primes) to
// 15 (all four primes), using a bitmask of up to four bits.
let prime_set = [0, 0, 1<<0, 1<<1, 0, 1<<2, 0, 1<<3, 0, 0]

// The possible digits that could
// follow a digit
function get_valid_digits(digit){
  if (digit == 0)
    return [0, 2, 3, 4, 5, 6, 7, 8, 9]
  else if ([2, 4, 8].includes(digit))
    return [0, 2, 4, 6, 8]
  else if ([3, 9].includes(digit))
    return [0, 3, 6, 9]
  else if (digit == 6)
    return [0, 2, 3, 4, 6, 8, 9]
  else if (digit == 5)
    return [0, 5]
  else if (digit == 7)
    return [0, 7]
}

// Build the table bottom-up

// Single digits
for (let i of xrange(10)){
  let mod_key = mod_keys[[i % 2, i % 3, i % 5, i % 7]]
  let length = 1
  let l_digit = i
  let prime_comb = prime_set[i]
  table[mod_key][l_digit][length][prime_comb] = 1
}

// Everything else
// For demonstration, we just table up to 6 digits
// since either JavaScript, this program, or both seem
// to be too slow for a full demo.
for (let length of xrange(2, 6)){
  // We're appending a new left digit
  for (let new_l_digit of xrange(0, 10)){
    // The digit 1 is never valid
    if (new_l_digit == 1)
      continue

    // The possible digits that could
    // be to the right of our new left digit      
    let ds = get_valid_digits(new_l_digit)

    // For each possible digit to the right
    // of our new left digit, iterate over all
    // the combinations of primes and remainder combinations.
    // The ones that are populated are valid paths, the
    // sum of which can be aggregated for each resulting
    // new combination of primes and remainders.
    for (let l_digit of ds){
      for (let p_comb of xrange(16)){
        for (let m_key of xrange(210)){
          new_prime_comb = prime_set[new_l_digit] | p_comb
          // suffix's remainder combination
          let [m2, m3, m5, m7] = mod_combs[m_key]
          // new remainder combination
          let m = Math.pow(10, length - 1) * new_l_digit
          let new_mod_key = mod_keys[[(m + m2) % 2, (m + m3) % 3, (m + m5) % 5, (m + m7) % 7]]

          // Aggregate any populated entries into the new
          // table entry
          table[new_mod_key][new_l_digit][length][new_prime_comb] += table[m_key][l_digit][length - 1][p_comb]
        }
      }
    }
  }
}


// If we need only a subset of the mods set to
// zero, we need to check all instances where
// this subset is zero. For example,
// for the prime combination, [2, 3], we need to
// check all mod combinations where the first two
// are zero since we don't care about the remainders
// for 5 and 7: [0,0,0,0], [0,0,0,1],... [0,0,4,6]
// Return all needed combinations given some
// predetermined, indexed remainders.
function prime_comb_to_mod_keys(remainders){
  let mod_map = [2, 3, 5, 7]
  let mods = []
  for (let i of xrange(4))
    mods.push(!remainders.hasOwnProperty(i) ? mod_map[i] - 1 : 0)
  
  function f(ms, i){
    if (i == ms.length){
      for (let idx in remainders)
        ms[idx] = remainders[idx]
      return [mod_keys[ms]]
    }    
    let result = []
    for (let m=ms[i] - 1; m>=0; m--){
      let _ms = ms.slice()
      _ms[i] = m
      result = result.concat(f(_ms, i + 1))
    }
    return result.concat(f(ms, i + 1))
  }
  return f(mods, 0)
}

function get_matching_mods(prefix, len_suffix, prime_comb){
  let ps = [2, 3, 5, 7]
  let actual_prefix = Math.pow(10, len_suffix) * prefix
  let remainders = {}
  for (let i in xrange(4)){
    if (prime_comb & (1 << i))
      remainders[i] = (ps[i] - (actual_prefix % ps[i])) % ps[i]
  }
  return prime_comb_to_mod_keys(remainders)
}

// A brute-force function to check the
// table is working. Returns a list of
// valid numbers of 'length' digits
// given a prefix.
function confirm(prefix, length){
  let result = [0, []]
  let ps = [0, 0, 2, 3, 0, 5, 0, 7, 0, 0]
  let p_len = String(prefix).length

  function check(suffix){
    let num = Math.pow(10, length - p_len) * prefix + suffix
    let temp = num
    prev = 0
    while (temp){
      let d = temp % 10
      if (d == 1 || gcd(prev, d) == 1 || (ps[d] && num % d))
        return [0, []]
      prev = d
      temp = ~~(temp / 10)
    }
    return [1, [num]]
  }

  for (suffix of xrange(Math.pow(10, length - p_len))){
    let [a, b] = check(suffix)
    result[0] += a
    result[1] = result[1].concat(b)
  }
  return result
}

function get_prime_comb(prefix){
  let prime_comb = 0
  while (prefix){
    let d = prefix % 10
    prime_comb |= prime_set[d]
    prefix = ~~(prefix / 10)
  }
  return prime_comb
}

// A function to test the table
// against the brute-force method.
// To match a prefix with the number
// of valid suffixes of a chosen length
// in the table, we want to aggregate all
// prime combinations for all valid digits,
// where the remainders for each combined
// prime combination (prefix with suffix)
// sum to zero (with the appropriate mod).
function test(prefix, length, show=false){
  let r_digit = prefix % 10
  let len_suffix = length - String(prefix).length
  let prefix_prime_comb = get_prime_comb(prefix)

  let ds = get_valid_digits(r_digit)
  let count = 0

  for (let l_digit of ds){
    for (let prime_comb of xrange(16)){
      for (let i of get_matching_mods(prefix, len_suffix, prefix_prime_comb | prime_comb)){
        let v = table[i][l_digit][len_suffix][prime_comb]
        count += v
      }
    }
  }

  let c = confirm(prefix, length)
  
  return `${ count }, ${ c[0] }${ show ? ': ' + c[1] : '' }`
}

// Arbitrary prefixes
for (let length of [3, 4]){
  for (let prefix of [2, 30]){
    console.log(`prefix, length: ${ prefix }, ${ length }`)
    console.log(`tabled, brute-force: ${ test(prefix, length, true) }\n\n`)
  }
}

let length = 6
for (let l_digit=2; l_digit<10; l_digit++){
  console.log(`prefix, length: ${ l_digit }, ${ length }`)
  console.log(`tabled, brute-force: ${ test(l_digit, length) }\n\n`)
}

这篇关于给定范围内存在多少个PR编号?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆