From: mukesh tiwari on
Hello Everyone. I am trying to solve a problem on SPOJ (https://
www.spoj.pl/problems/FACT0/)but i am getting time limit exceed.I
implemented pollard rho algorithm given on wikipedia.(http://
en.wikipedia.org/wiki/Pollard%27s_rho_algorithm) Is there any other
faster version of this algorithm.Here is the full code but only major
part is Pollard and factor function.
Thank you

#include <vector>
#include <list>
#include <map>
#include <set>
#include <deque>
#include <queue>
#include <stack>
#include <bitset>
#include <algorithm>
#include <functional>
#include <numeric>
#include <utility>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cctype>
#include <string>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <ctime>
using namespace std;
typedef long long ll;
bool B[1000000];
vector<long long>v,p;

void isprime()
{
B[0]=B[1]=1;
for(int i=2;i*i<1000000;i++)
if(!B[i]) for(int j=i*i;j<1000000;j+=i) B[j]=1;

for(int i=0;i<1000000;i++) if(!B[i]) p.push_back((long long)i);
//for(int i=0;i<10;i++) cout<<p[i]<<" ";
//cout<<endl;
}


long long mulmod(long long a,long long b,long long c){
long long x = 0,y=a%c;
while(b > 0){
if(b%2 == 1){
x = (x+y)%c;
}
y = (y*2)%c;
b /= 2;
}
return x%c;
}

ll modulo(ll a,ll b,ll c){
ll x=1,y=a; // ll is taken to avoid overflow of intermediate
results
while(b > 0){
if(b%2 == 1){
x=mulmod(x,y,c);
}
y = mulmod(y,y,c); // squaring the base
b /= 2;
}
return x%c;
}
bool Miller(long long p,int iteration){
if(p<2){
return false;
}
if(p!=2 && p%2==0){
return false;
}
long long s=p-1;
while(s%2==0){
s/=2;
}
for(int i=0;i<iteration;i++){
long long a=rand()%(p-1)+1,temp=s;
long long mod=modulo(a,temp,p);
while(temp!=p-1 && mod!=1 && mod!=p-1){
mod=mulmod(mod,mod,p);
temp *= 2;
}
if(mod!=p-1 && temp%2==0){
return false;
}
}
return true;
}


ll PollardRho(ll n)
{
//cout<<n<<endl;
if(n%2==0) return 2LL;
ll x=(ll) random();
ll y=x;
ll c=(ll)random();
ll d;
do
{
x=((x*x)%n+c)%n;
//if(x<0) cout<<x<<endl;
y=((y*y)%n+c)%n;
y=((y*y)%n+c)%n;
d=__gcd(abs(x-y),n);
//cout<<"d= "<<d<<endl;
}while(d==1);
return d;
}

void factor(ll n)
{
if(n==1) return ;
if(Miller(n,1)) { v.push_back(n); return ;}
ll div=PollardRho(n);
factor(div);
factor(n/div);
}

int main()
{


ll n;
isprime();
while(scanf("%lld",&n) && n!=0)
{
v.clear();
for(int i=0;i<p.size() && p[i]*p[i]<=n;)
{
if(n%p[i]==0)
{
v.push_back(p[i]);
n/=p[i];
}
else i++;
}
//cout<<n<<endl;
factor(n);
sort(v.begin(),v.end());
v.push_back(0);
int p=1;
for(int i=0;i+1<v.size();i++)
{
if(v[i]==v[i+1]) p++;
else
{
cout<<v[i]<<"^"<<p;
if(i+2<v.size()) printf(" ");
else printf("\n");
p=1;
}
}

}
}
From: Richard Heathfield on
mukesh tiwari wrote:
> Hello Everyone. I am trying to solve a problem on SPOJ (https://
> www.spoj.pl/problems/FACT0/)but i am getting time limit exceed.I
> implemented pollard rho algorithm given on wikipedia.(http://
> en.wikipedia.org/wiki/Pollard%27s_rho_algorithm) Is there any other
> faster version of this algorithm.Here is the full code but only major
> part is Pollard and factor function.
> Thank you

<snip>

> void isprime()
> {
> B[0]=B[1]=1;
> for(int i=2;i*i<1000000;i++)
> if(!B[i]) for(int j=i*i;j<1000000;j+=i) B[j]=1;

Once you've dealt with 2, you only need worry about odd numbers. In
fact, once you've dealt with 3, you need only test numbers of the form
6k-1 and 6k+1. That should triple the speed of your loop.

--
Richard Heathfield <http://www.cpax.org.uk>
Email: -http://www. +rjh@
"Usenet is a strange place" - dmr 29 July 1999
Sig line vacant - apply within
From: websnarf on
On Feb 4, 12:36 pm, mukesh tiwari <mukeshtiwari.ii...(a)gmail.com>
wrote:
> Hello Everyone. I am trying to solve a problem on SPOJ (https://www.spoj.pl/problems/FACT0/)buti am getting time limit exceed.I
> implemented pollard rho algorithm given on wikipedia.(http://
> en.wikipedia.org/wiki/Pollard%27s_rho_algorithm) Is there any other
> faster version of this algorithm.Here is the full code but only major
> part is Pollard and factor function.
> Thank you

The problem is that your mulmod() is too slow. You are doing
multiplication by bit test, shift and add or something like that.
That's a horrible way of doing multiplication to a long word with a
modulo. You are doing one % per on-bit of the input. The / %
operators are the slowest of the basic operations of your CPU.

One thing you can do is implement a hard coded two-digit Karatsuba's
method for the multiplication, to reduce your 128-bit output to
calculating 3 64-bit outputs (with 32-bit inputs.) Then implement a
"two-digit division" using successive 64 bit division estimations. I
am sure you would never need to do more than 3 divisions, and can
probably get away with 2 (but I have not tried it myself to be sure.)

The other more standard method that is widely used is something called
"Barrett modular reduction". I have not implemented this myself, but
apparently that's the algorithm of choice for this.

If you can guarantee that the integers are 32 bits or less, then you
can use my implementation:

http://www.azillionmonkeys.com/qed/primeat.zip

which includes a primality test. Its for C, but easily adapted to
Java or C++.

Also note, that if your machine is actually running in 32 bit mode
instead of 64 bit mode, but you are using these 64-bit primitives,
then your results will be about 4 times slower.

--
Paul Hsieh
http://www.pobox.com/~qed/
http://bstring.sf.net/

> #include <vector>
> #include <list>
> #include <map>
> #include <set>
> #include <deque>
> #include <queue>
> #include <stack>
> #include <bitset>
> #include <algorithm>
> #include <functional>
> #include <numeric>
> #include <utility>
> #include <sstream>
> #include <iostream>
> #include <iomanip>
> #include <cstdio>
> #include <cmath>
> #include <cstdlib>
> #include <cctype>
> #include <string>
> #include <cstring>
> #include <cstdio>
> #include <cmath>
> #include <cstdlib>
> #include <ctime>
> using namespace std;
> typedef long long ll;
> bool B[1000000];
> vector<long long>v,p;
>
> void isprime()
>         {
>                 B[0]=B[1]=1;
>                 for(int i=2;i*i<1000000;i++)
>                         if(!B[i]) for(int j=i*i;j<1000000;j+=i) B[j]=1;
>
>                 for(int i=0;i<1000000;i++) if(!B[i]) p.push_back((long long)i);
>                 //for(int i=0;i<10;i++) cout<<p[i]<<" ";
>                 //cout<<endl;
>         }
>
> long long mulmod(long long a,long long b,long long c){
>     long long x = 0,y=a%c;
>     while(b > 0){
>         if(b%2 == 1){
>             x = (x+y)%c;
>         }
>         y = (y*2)%c;
>         b /= 2;
>     }
>     return x%c;
>
> }
>
> ll modulo(ll a,ll b,ll c){
>     ll x=1,y=a; // ll is taken to avoid overflow of intermediate
> results
>     while(b > 0){
>         if(b%2 == 1){
>             x=mulmod(x,y,c);
>         }
>         y = mulmod(y,y,c); // squaring the base
>         b /= 2;
>     }
>     return x%c;}
>
> bool Miller(long long p,int iteration){
>     if(p<2){
>         return false;
>     }
>     if(p!=2 && p%2==0){
>         return false;
>     }
>     long long s=p-1;
>     while(s%2==0){
>         s/=2;
>     }
>     for(int i=0;i<iteration;i++){
>         long long a=rand()%(p-1)+1,temp=s;
>         long long mod=modulo(a,temp,p);
>         while(temp!=p-1 && mod!=1 && mod!=p-1){
>             mod=mulmod(mod,mod,p);
>             temp *= 2;
>         }
>         if(mod!=p-1 && temp%2==0){
>             return false;
>         }
>     }
>     return true;
>
> }
>
> ll PollardRho(ll n)
>         {
>                 //cout<<n<<endl;
>                 if(n%2==0) return 2LL;
>                 ll x=(ll) random();
>                 ll y=x;
>                 ll c=(ll)random();
>                 ll d;
>                 do
>                 {
>                         x=((x*x)%n+c)%n;
>                         //if(x<0) cout<<x<<endl;
>                         y=((y*y)%n+c)%n;
>                         y=((y*y)%n+c)%n;
>                         d=__gcd(abs(x-y),n);
>                         //cout<<"d= "<<d<<endl;
>                 }while(d==1);
>                 return d;
>         }
>
> void factor(ll n)
>         {
>                 if(n==1) return ;
>                 if(Miller(n,1)) { v.push_back(n); return ;}
>                 ll div=PollardRho(n);
>                 factor(div);
>                 factor(n/div);
>         }
>
> int main()
>         {
>
>                 ll n;
>                 isprime();
>                 while(scanf("%lld",&n) && n!=0)
>                 {
>                         v.clear();
>                         for(int i=0;i<p.size() && p[i]*p[i]<=n;)
>                         {
>                                 if(n%p[i]==0)
>                                  {
>                                         v.push_back(p[i]);
>                                         n/=p[i];
>                                  }
>                                 else i++;
>                         }
>                         //cout<<n<<endl;
>                         factor(n);
>                         sort(v.begin(),v.end());
>                         v.push_back(0);
>                         int p=1;
>                         for(int i=0;i+1<v.size();i++)
>                         {
>                                 if(v[i]==v[i+1]) p++;
>                                 else
>                                 {
>                                         cout<<v[i]<<"^"<<p;
>                                         if(i+2<v.size()) printf(" ");
>                                         else printf("\n");
>                                         p=1;
>                                 }
>                         }
>
>                 }
>         }

From: aslan on

"mukesh tiwari" <mukeshtiwari.iiitm(a)gmail.com>, iletisinde sunu yazdi,
news:d618772c-845c-47e5-9d94-e836c92fce3a(a)m24g2000prn.googlegroups.com...
> Hello Everyone. I am trying to solve a problem on SPOJ (https://
> www.spoj.pl/problems/FACT0/)but i am getting time limit exceed.I
> implemented pollard rho algorithm given on wikipedia.(http://
> en.wikipedia.org/wiki/Pollard%27s_rho_algorithm) Is there any other
> faster version of this algorithm.Here is the full code but only major
> part is Pollard and factor function.
> Thank you
>
> #include <vector>
> #include <list>
> #include <map>
> #include <set>
> #include <deque>
> #include <queue>
> #include <stack>
> #include <bitset>
> #include <algorithm>
> #include <functional>
> #include <numeric>
> #include <utility>
> #include <sstream>
> #include <iostream>
> #include <iomanip>
> #include <cstdio>
> #include <cmath>
> #include <cstdlib>
> #include <cctype>
> #include <string>
> #include <cstring>
> #include <cstdio>
> #include <cmath>
> #include <cstdlib>
> #include <ctime>
> using namespace std;
> typedef long long ll;
> bool B[1000000];
> vector<long long>v,p;
>
> void isprime()
> {
> B[0]=B[1]=1;
> for(int i=2;i*i<1000000;i++)
> if(!B[i]) for(int j=i*i;j<1000000;j+=i) B[j]=1;
>
> for(int i=0;i<1000000;i++) if(!B[i]) p.push_back((long long)i);
> //for(int i=0;i<10;i++) cout<<p[i]<<" ";
> //cout<<endl;
> }
>
>
> long long mulmod(long long a,long long b,long long c){
> long long x = 0,y=a%c;
> while(b > 0){
> if(b%2 == 1){
> x = (x+y)%c;
> }
> y = (y*2)%c;
> b /= 2;
> }
> return x%c;
> }
>
> ll modulo(ll a,ll b,ll c){
> ll x=1,y=a; // ll is taken to avoid overflow of intermediate
> results
> while(b > 0){
> if(b%2 == 1){
> x=mulmod(x,y,c);
> }
> y = mulmod(y,y,c); // squaring the base
> b /= 2;
> }
> return x%c;
> }
> bool Miller(long long p,int iteration){
> if(p<2){
> return false;
> }
> if(p!=2 && p%2==0){
> return false;
> }
> long long s=p-1;
> while(s%2==0){
> s/=2;
> }
> for(int i=0;i<iteration;i++){
> long long a=rand()%(p-1)+1,temp=s;
> long long mod=modulo(a,temp,p);
> while(temp!=p-1 && mod!=1 && mod!=p-1){
> mod=mulmod(mod,mod,p);
> temp *= 2;
> }
> if(mod!=p-1 && temp%2==0){
> return false;
> }
> }
> return true;
> }
>
>
> ll PollardRho(ll n)
> {
> //cout<<n<<endl;
> if(n%2==0) return 2LL;
> ll x=(ll) random();
> ll y=x;
> ll c=(ll)random();
> ll d;
> do
> {
> x=((x*x)%n+c)%n;
> //if(x<0) cout<<x<<endl;
> y=((y*y)%n+c)%n;
> y=((y*y)%n+c)%n;
> d=__gcd(abs(x-y),n);
> //cout<<"d= "<<d<<endl;
> }while(d==1);
> return d;
> }
>
> void factor(ll n)
> {
> if(n==1) return ;
> if(Miller(n,1)) { v.push_back(n); return ;}
> ll div=PollardRho(n);
> factor(div);
> factor(n/div);
> }
>
> int main()
> {
>
>
> ll n;
> isprime();
> while(scanf("%lld",&n) && n!=0)
> {
> v.clear();
> for(int i=0;i<p.size() && p[i]*p[i]<=n;)
> {
> if(n%p[i]==0)
> {
> v.push_back(p[i]);
> n/=p[i];
> }
> else i++;
> }
> //cout<<n<<endl;
> factor(n);
> sort(v.begin(),v.end());
> v.push_back(0);
> int p=1;
> for(int i=0;i+1<v.size();i++)
> {
> if(v[i]==v[i+1]) p++;
> else
> {
> cout<<v[i]<<"^"<<p;
> if(i+2<v.size()) printf(" ");
> else printf("\n");
> p=1;
> }
> }
>
> }
> }

This one outputs the prime factorisation for the given example:

#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <memory.h>
#include <string.h>
#include <time.h>

typedef __int64 int64;
struct timer
{
clock_t t;
timer() { t = clock(); }
~timer() { printf("runtime %.3f secs\n", getTime()); }
double getTime() { return
((double)clock()-(double)t)/(double)CLOCKS_PER_SEC; }
};

void get_divisors(int64 n)
{
printf("%I64d = ",n);
if (!(n&1))
{
int np=1;
while (n/=2, !(n&1))
++np;
printf("2^%d ", np);
}
if (!(n%3))
{
int np=1;
while (n/=3, !(n%3))
++np;
printf("3^%d ", np);
}
int64 p=1, a=2, hi=sqrt(n)+1;
while (a=6-a, p+=a, p<=hi)
{
if (!(n%p))
{
int np=1;
while (n/=p, !(n%p))
++np;
printf("%I64d^%d ", p, np);
}
}
if (n>1)
printf("%I64d^1 ", n);
printf("\n");
}

int main(int argc, char**argv)
{
timer t;
get_divisors(3111989);
get_divisors(13091989);
get_divisors(2432902008176640000);
get_divisors(77145199750673);

return 0;
}

/*
3111989 = 317^1 9817^1
13091989 = 17^2 89^1 509^1
2432902008176640000 = 2^18 3^8 5^4 7^2 11^1 13^1 17^1 19^1
77145199750673 = 328439^1 234884407^1
runtime 0.048 secs
Press any key to continue
*/