对于给定的数 N,我如何找到 x, S.T 乘积 (x 和 x 的因子数) = N?

For a given number N, how do I find x, S.T product of (x and no. of factors to x) = N?

本文关键字:乘积 何找      更新时间:2023-10-16

要查找数字因子,我正在使用函数void primeFactors(int n)

# include <stdio.h>
# include <math.h>
# include <iostream>
# include <map>
using namespace std; 
// A function to print all prime factors of a given number n
map<int,int> m;
void primeFactors(int n)
{
// Print the number of 2s that divide n
while (n%2 == 0)
{
printf("%d ", 2);
m[2] += 1;
n = n/2;
}
// n must be odd at this point.  So we can skip one element (Note i = i +2)
for (int i = 3; i <= sqrt(n); i = i+2)
{
// While i divides n, print i and divide n
while (n%i == 0)
{
int k = i;
printf("%d ", i);
m[k] += 1; 
n = n/i;
}
}
// This condition is to handle the case whien n is a prime number
// greater than 2
if (n > 2)
m[n] += 1; 
printf ("%d ", n);

cout << endl;
}
/* Driver program to test above function */
int main()
{
int n = 72;
primeFactors(n);
map<int,int>::iterator it;
int to = 1;
for(it = m.begin(); it != m.end(); ++it){
cout << it->first << " appeared " << it->second << " times "<< endl;
to *= (it->second+1);
}
cout << to << " total facts" << endl;
return 0;
}

你可以在这里查看。Test case n = 72. http://ideone.com/kaabO0

如何使用上述算法解决上述问题。(可以进一步优化吗?我还必须考虑大数字。

我想做什么.. 以N =864为例,我们发现 X = 72 为 (72 * 12 (因子数)) = 864)

大数有一个素数分解算法,但实际上它并不经常用于编程竞赛。
我解释了 3 种方法,您可以使用此算法实现。
如果你实现了,我建议解决这个问题。
注意:在这个答案中,我使用整数Q作为查询的数量。

O(Q * sqrt(N)) 每个查询的解
你的算法的时间复杂度是O(n^0.5).
但是您正在使用int(32位)实现,因此您可以使用长长整数。
这是我的实现: http://ideone.com/gkGkkP

O(sqrt(maxn) * log(log(maxn))+ Q * sqrt(maxn)/log(maxn)) 算法
您可以减少循环次数,因为合数对于整数 i 不是必需的。
所以,你只能在循环中使用质数。

算法:

  1. 用埃拉托色尼筛子计算所有素数 <= sqrt(n)。时间复杂度为 O(sqrt(maxn) * log(log(maxn)))。
  2. 在查询中,循环 i (i <= sqrt(n) 并且 i 是质数)。有效整数 i 与素数定理约为 sqrt(n)/log(n),因此每个查询的时间复杂度为 O(sqrt(n)/log(n))。

更高效的算法
世界上有更高效的算法,但在编程竞赛中并不经常使用。
如果你在互联网或维基百科上勾选"整数分解算法",你可以找到像波拉德的s-rho或通用数字字段筛这样的算法。

好吧,我将向您展示代码。

# include <stdio.h>
# include <iostream>
# include <map>
using namespace std;
const long MAX_NUM = 2000000;
long prime[MAX_NUM] = {0}, primeCount = 0;
bool isNotPrime[MAX_NUM] = {1, 1}; // yes. can be improve, but it is useless when sieveOfEratosthenes is end
void sieveOfEratosthenes() {
//@see https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes
for (long i = 2; i < MAX_NUM; i++) { // it must be i++
if (!isNotPrime[i]) //if it is prime,put it into prime[]
prime[primeCount++] = i;
for (long j = 0; j < primeCount && i * prime[j] < MAX_NUM; j++) { /*foreach prime[]*/
//            if(i * prime[j] >= MAX_NUM){ // if large than MAX_NUM break
//                break;
//            }
isNotPrime[i * prime[j]] = 1;  // set i * prime[j] not a prime.as you see, i * prime[j]
if (!(i % prime[j])) //if this prime the min factor of i,than break.
// and it is the answer why not i+=( (i & 1) ? 2 : 1).
// hint : when we judge 2,prime[]={2},we set 2*2=4 not prime
//        when we judge 3,prime[]={2,3},we set 3*2=6 3*3=9 not prime
//        when we judge 4,prime[]={2,3},we set 4*2=8 not prime (why not set 4*3=12?)
//        when we judge 5,prime[]={2,3,5},we set 5*2=10 5*3=15 5*5=25 not prime
//        when we judge 6,prime[]={2,3,5},we set 6*2=12 not prime,than we can stop
// why not put 6*3=18 6*5=30 not prime? 18=9*2 30=15*2.
// this code can make each num be set only once,I hope it can help you to understand
// this is difficult to understand but very useful.
break;
}
}
}
void primeFactors(long n)
{
map<int,int> m;
map<int,int>::iterator it;
for (int i = 0; prime[i] <= n; i++) // we test all prime small than n , like 2 3 5 7... it musut be i++
{
while (n%prime[i] == 0)
{
cout<<prime[i]<<" ";
m[prime[i]] += 1;
n = n/prime[i];
}
}
cout<<endl;
int to = 1;
for(it = m.begin(); it != m.end(); ++it){
cout << it->first << " appeared " << it->second << " times "<< endl;
to *= (it->second+1);
}
cout << to << " total facts" << endl;
}
int main()
{
//first init for calculate all prime numbers,for example we define MAX_NUM = 2000000
// the result of prime[] should be stored, you primeFactors will use it
sieveOfEratosthenes();
//second loop for i (i*i <= n and i is a prime number). n<=MAX_NUM
int n = 72;
primeFactors(n);
n = 864;
primeFactors(n);
return 0;
}

我最好的性能机会,而不会被特殊算法过火。

Erathostenes的seive-下面的复杂性是O(N*log(log(N)))-因为内部j循环从i*i而不是i开始。

#include <vector>
using std::vector;
void erathostenes_sieve(size_t upToN, vector<size_t>& primes) {
primes.clear();
vector<bool> bitset(upToN+1, true); // if the bitset[i] is true, the i is prime
bitset[0]=bitset[1]=0;
// if i is 2, will jump to 3, otherwise will jump on odd numbers only
for(size_t i=2; i<=upToN; i+=( (i&1) ? 2 : 1)) {
if(bitset[i]) { // i is prime
primes.push_back(i);
// it is enough to start the next cycle from i*i, because all the 
// other primality tests below it are already performed:
// e.g:
// - i*(i-1) was surely marked non-prime when we considered multiples of 2
// - i*(i-2) was tested at (i-2) if (i-2) was prime or earlier (if non-prime)
for(size_t j=i*i; j<upToN; j+=i) {
bitset[j]=false; // all multiples of the prime with value of i
// are marked non-prime, using **addition only**
}
}
}
}

现在基于primes分解(在排序向量中设置)。在此之前,让我们来看看sqrt很贵但一大堆乘法不贵的神话。

首先,让我们注意 sqrt 不再那么昂贵:在较旧的 CPU-es (x86/32b) 上,它曾经是除法的两倍(modulo操作是除法),在较新的架构上,CPU 成本相等的。由于因式分解是关于一次又一次%运算,因此人们仍然可以不时地考虑sqrt(例如,是否以及何时使用它可以节省 CPU 时间)。

例如,假设primes有 10000 个条目,请考虑以下N=65537(即第 6553 个素数)的代码

size_t limit=std::sqrt(N);
size_t largestPrimeGoodForN=std::distance(
primes.begin(), 
std::upper_limit(primes.begin(), primes.end(), limit) // binary search
);
// go descendingly from limit!!!
for(int i=largestPrimeGoodForN; i>=0; i--) { 
// factorisation loop
}

我们有:

1
  • 平方 (等于 1modulo),
  • 10000个条目中进行 1 次搜索 - 最多 14 个步骤,每个步骤涉及 1 个比较、1 个右移除以 2 和 1 个递增/递减 - 所以假设成本等于 14-20 次乘法(如果有的话)
  • 1 因std::distance而有所不同。

那么,最大成本 - 1div 和 20 muls?我很慷慨。

另一边:

for(int i=0; primes[i]*primes[i]<N; i++) {
// factorisation code
}

看起来简单得多,但由于N=65537是素数,我们将遍历所有循环直到i=64(在那里我们会找到导致循环中断的第一个素数) - 总共 65 次乘法。
尝试使用更高的质数,我向您保证 1 sqrt+1 二进制搜索的成本比以更简单的周期形式吹捧为更好性能解决方案的方式上的所有乘法更好地利用 CPU 周期


所以,回到因式分解代码:

#include <algorithm>
#include <math>
#include <unordered_map>
void factor(size_t N, std::unordered_map<size_t, size_t>& factorsWithMultiplicity) {
factorsWithMultiplicity.clear();
while( !(N & 1) ) { // while N is even, cheaper test than a '% 2'
factorsWithMultiplicity[2]++;
N = N >> 1; // div by 2 of an unsigned number, cheaper than the actual /2
}
// now that we know N is even, we start using the primes from the sieve
size_t limit=std::sqrt(N); // sqrt is no longer *that* expensive,
vector<size_t> primes;
// fill the primes up to the limit. Let's be generous, add 1 to it
erathostenes_sieve(limit+1, primes);
// we know that the largest prime worth checking is
// the last element of the primes.
for(
size_t largestPrimeIndexGoodForN=primes.size()-1;
largestPrimeIndexGoodForN<primes.size(); // size_t is unsigned, so after zero will underflow
// we'll handle the cycle index inside
) {
bool wasFactor=false;
size_t factorToTest=primes[largestPrimeIndexGoodForN];
while( !( N % factorToTest) ) {
wasFactor=true;// found one
factorsWithMultiplicity[factorToTest]++;
N /= factorToTest;
}
if(1==N) { // done
break;
}
if(wasFactor) { // time to resynchronize the index
limit=std::sqrt(N);
largestPrimeIndexGoodForN=std::distance(
primes.begin(),
std::upper_bound(primes.begin(), primes.end(), limit)
);
}
else { // no luck this time
largestPrimeIndexGoodForN--;
}
} // done the factoring cycle
if(N>1) { // N was prime to begin with
factorsWithMultiplicity[N]++;
}
}