找出对i和j的对数,使得A [i]和A [j]的乘积有效地划分K

时间:2016-10-19 11:00:30

标签: c++ product division number-theory

假设数组A中有整数列表。
给定另一个包含查询的数组Q.
对于每个查询K,您需要找到对i和j的对数,使得A [i]和A [j]的乘积除以K.

如何在没有任何强力方法的情况下有效地完成这项工作?

例如:

鉴于 答:2 5 6 2 3
问:12 7 100 200

输出:5 0 2 3

说明:

除以12的对的数量为:(1,3),(1,4),(1,5),(3,4),(4,5)
除以7的对数:无(0)等......

如何在没有任何强力方法的情况下有效地完成这项工作?

3 个答案:

答案 0 :(得分:2)

将所有因素归结为素数的幂。

对于每个查询值,构建N维数组,其中N是查询值的主要因子。每个维度都有k + 1个条目,其中k是相应素数的幂。

绘制此数组中的每个潜在因子,将其位置递增1.如果在数组外部,则丢弃。

使用n维扫描将cdf存储在每个维度的每个维度中。总共不到40个条目,所以这应该足够快。

每个潜在因素的“反向”位置。如果I_j和I_j无效,请通过加倍素数手动检查它并减去一次。

您可以预先计算每个目标或每个源,并构建一个巨大的阵列。但那可能太过分了。

答案 1 :(得分:0)

这样的快速拍摄:

您可以»预编译«所有可能S结果的列表A[i] * A[j],并过滤该列表中的双重内容;

A = [1,2,3];
Q = [3,4,5]

All possible results:

1 * [2,3] => 2,3
2 * [1,3] => 2,6
3 * [1,2] => 3,6 //these are 6 values to test for each

S = [2,3,6] //here are only three unique

Than:

2/2, 2/3, 2/6 => 1
3/2, 3/3, 3/6 => 1
6/2, 6/3, 6/6 => 3

答案 2 :(得分:0)

A可能会这样做:

  1. 创建一个哈希映射 H ,其中包含所有 A [i] A [j] 产品的集合 A 的。 (如果您愿意,可以使用2D阵列)。
  2. 将零初始化 m 设为 K 中的对数。然后,对于 K 的每个因子,在 H 中找到它。如果在那里,则按1增加 m
  3.   

    运行时间:O(N * N) + c * Q。其中 N 是数组 A 的大小;    c 是查询值的平均因子数; Q是查询次数。

    在C ++中:

    #include <cmath>
    #include <vector>
    #include <iostream>
    #include <unordered_map>
    
    //returns a hashmap, containing all allowed pairs in vec
    std::unordered_map<int, int> build_lookup_table(const std::vector<int>& vec){
        std::unordered_map<int, int> table(vec.size());
        for(std::size_t row = 0; row < vec.size(); row++)
            for(std::size_t col = row + 1; col < vec.size(); col++)
                ++table[vec[row] * vec[col]];
        return table;
    }
    
    //a fairly fast and simple way to quickly get factors without using % modulus
    std::vector<int> get_factors(const int k){
        std::vector<int> vec;
        const int limit = std::sqrt(k);
        for(int i = 1; i <= limit; i++){
            int val = k / i;
            if(val * i == k)
                vec.push_back(i), vec.push_back(val);
        }
        if(limit * limit == k)      //if its a perfect square
            vec.pop_back();
        return vec;
    }
    
    
    int main(){
        std::vector<int> A{ 2, 5, 6, 2, 3 };
        std::vector<int> Q{12, 20, 7, 10, 200 };
        std::vector<int> ans(Q.size());
    
        const auto lookup_table = build_lookup_table(A);
        for(auto k : Q){
            auto pairs = 0;
            for(auto factor : get_factors(k)){
                auto iter = lookup_table.find(factor);
                pairs += iter != lookup_table.end() ? iter->second : 0;
            }
            ans.push_back(pairs);
        }
    
        for(auto x : ans)
            std::cout << x << ' ';
        std::cout << std::endl;
    }
    

    See a Demo