My question is write an efficient algorithm to check whether a given number n is of the form ab where a, b are integers >= 2. I have tried the following but it is not time efficient.
int cnt = 0;
long long i, sq = sqrt(n);
for (i = 2; i <= sq; i++) {
if (n % i == 0) {
cnt++;
n = n / i;
while (n % i == 0) {
n /= i;
cnt++;
}
if (n == 1) {
break;
}
}
}
if (cnt >= 2) {
return true;
}
return false;
I'm assuming you meant pow(a, b) not a^b, since ^ in C/C++ is the XOR operator.
Your problem is known as detecting perfect powers and there is a lot of literature you can find in the internet.
For example: Detecting perfect powers in linear time by Daniel Bernstein.
You can both fix your code and speed it up considerably by replacing:
if (n == 1) break;
with
return (n == 1);
Then since you went to the trouble of computing sqrt(n), might as well have an early exit for perfect squares:
if (n == sq * sq) return true;
Idea:
if n = 3^5 then:
ln(n) / ln(3) = 5
exp( ln(n) / 5 ) = 3
Sample JavaScript code, open inspector/console for results (easily convertible to C):
http://jsfiddle.net/8wuUK/
function powerSplit( n ){
console.log('n =', n);
var log = Math.log, exp = Math.exp, abs = Math.abs,
floor = Math.floor, round = Math.round;
var epsilon = 0.001;
var logn = log( n );
var pow = floor( log(n) / log(2) ) + 1;
do{
pow --;
var base = exp( logn / pow );
var intbase = round( base );
if( abs( base - intbase ) > epsilon ) continue;
//console.log( base, intbase, pow, isExactPower( n, intbase ) );
if( isExactPower( n, intbase )) return 'n = ' + intbase +' ^ ' + pow;
}while( pow >= 1 );
return 'n is not a power';
}
function isExactPower( n, base ){
while( n > 1 ){
if( n % base ) return false;
n /= base;
};
return true;
};
Related
Hi i am an amateur in programing, but i propose me to getting better and because that i start to solve problems in online judges and i don't know how to do a combinatorial analysis, i found some similar question but i can't apply to my code, if you are able to explain me how to do it, i will be incredibly grateful.
so here is the full text of the problem, translated of Portuguese to English. At end is my code.
To prove her scientific skills Princess Bubblegum learned to program using BMO (The best computer in the Candy kingdom) and like every programmer she fell in love with binary numbers.
Because of her addiction to binary numbers she loves decimal numbers that look like a binary number (i.e. a decimal number that contains only digits 0 and 1, for example 101) so given a decimal number N she wants to find a multiple of that number that looks like a number binary, but for some numbers it was taking a long time to find that multiple, even with the help of BMO. Because of her problem-solving addiction, she wasn't doing anything until she found this multiple. Perfect situation for the Earl of Lemongrab, who has taken over the Candy Kingdom. As Finn and Jake, the heroes of the Candy kingdom, can't do anything against the Count and know nothing about multiples, they asked to find the multiples and thus save the kingdom.
Prohibited
The input contains up to 2*10^5 lines, each line with an integer N (0 < N < 10^12), the number Princess Bubblegum wants to find the multiple M (M != 0), this number must be smaller than 10^12, otherwise it doesn't fit in the BMO architecture.
Exit
Print a single integer per line, if there are multiple multiples print the smallest one. If there is no solution print -1
#include <stdlib.h>
#include <math.h>
int main() // normal ways works fine but i have to do it faster, time limit is 2s//
//doing 11 fors works to but its have same tle problem//
{
long long int n, R, num, res, expo;
int b = 0, dig[11] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, E=0, an, anmax = 1024, reseter, cob, casa;
while (E < 200000)
{
E++;
num = 0;
scanf("%lld", &n); //I have to read a decimal number and from that found the smaller multiple number that is similar to a binary number, and cannot be 0//
res=n%10;
if ((res==1) || (res==0)) // in case the read number is already similar to binary, this works fine//
{ b=1;
for ( num=n;((num>0) && (b==1)); num=num/10)
{
res=num%10;
if ((res==1) || (res==0)){
b=1;
R=n;
}else
{
b=0;
R=-1;
}
}
}else{
if ((n > 0) && (n < 1000000000000))
{
if (n < 500000000000)
{
num = n;
for (expo = -1; num >= 1; expo++, num = num / 10)//so expo is a varieble to found the smaller house of input to made a number, its just for reduce cycles//
{
res = num % 10;
}
if (res > 1)
{
expo = expo + 1;
}
dig[expo] = 1;
R = ((dig[11] * 100000000000) + (dig[10] * 10000000000) + (dig[9] * 1000000000) + (dig[8] * 100000000) + (dig[7] * 10000000) + (dig[6] * 1000000) + (dig[5] * 100000) + (dig[4] * 10000) + (dig[3] * 1000) + (dig[2] * 100) + (dig[1] * 10) + (dig[0] * 1));
for (dig[expo] = 1; ((expo < 11) && (b == 0)); expo++)//// 1 is fixed value until no one of numbers is divisible//
{
anmax = pow(2, expo);//forget this line//
dig[expo] = 1;
for (casa = 0; ((casa < expo) && (b == 0)); casa++)//here is my problem i dont know how to alternate all values that can be ninary//
{ //this is my original idea to solve but this don't generate all possible values//
for (cob = 0; ((cob < 2) && (b == 0)); cob++)
{
dig[casa] = cob;
R = ((dig[11] * 100000000000) + (dig[10] * 10000000000) + (dig[9] * 1000000000) + (dig[8] * 100000000) + (dig[7] * 10000000) + (dig[6] * 1000000) + (dig[5] * 100000) + (dig[4] * 10000) + (dig[3] * 1000) + (dig[2] * 100) + (dig[1] * 10) + (dig[0] * 1));
if ((R % n) == 0)
{
b = 1;
}
}
}
if ((cob == 2) || (b==1))
{
for (reseter = expo; reseter >= 0; reseter--)//it works fine is just to start all values with 0 before its repeats//
{
dig[reseter] = 0;
}
}
}
}
else
{
R = -1;
}
if((R==11111111111) && ((n!=21649) || (n!=513239))){
R=-1; //its not important//
}
}else
{
R=-1;
}
}
// reset para proximos valores//
b = 0;
printf("%lld\n", R);
}
return 0;
}
I'm facing some difficulties in the last few days while trying to finish the following task, I hope you guys can assist :
I'm given a single number N, and I'm allowed to perform any of the two operations on N in each move :
One - If we take 2 integers where N = x * y , then we can change the value of N to the maximum between x and y.
Two - Decrease the value of N by 1.
I want to find the minimum number of steps to reduce N to zero.
This is what I have so far, I'm not sure what is the best way to implement the function to find the divisor (someFindDevisorFunction), and if this 'f' function would actually produce the required output.
int f(int n)
{
int div,firstWay,secondWay;
if(n == 0)
return 0;
div = SomefindDivisorFunction(n);
firstWay = 1 + f(n-1);
if(div != 1)
{
secondWay = 1 + f(div);
if (firstWay < secondWay)
return firstWay;
return secondWay;
}
return firstWay;
}
For example, if I enter the number 150 , the output would be :
75 - 25 - 5 - 4 - 2 - 1 - 0
I see this a recursive or iterative problem.
OP's approach hints at recursive.
A recursive solution follows:
At each step, code counts the steps of the various alternatives:
steps(n) = min(
steps(factor1_of_n) + 1,
steps(factor2_of_n) + 1,
steps(factor3_of_n) + 1,
...
steps(n-1) + 1)
The coded solution below is inefficient, but it does explore all possibilities and gets to the answer.
int solve_helper(int n, bool print) {
int best_quot = 0;
int best_quot_score = INT_MAX;
int quot;
for (int p = 2; p <= (quot = n / p); p++) {
int rem = n % p;
if (rem == 0 && quot > 1) {
int score = solve_helper(quot, false) + 1;
if (score < best_quot_score) {
best_quot_score = score;
best_quot = quot;
}
}
}
int dec_score = n > 0 ? solve_helper(n - 1, false) + 1 : 0;
if (best_quot_score < dec_score) {
if (print) {
printf("/ %d ", best_quot);
solve_helper(best_quot, true);
}
return best_quot_score;
}
if (print && n > 0) {
printf("- %d ", n - 1);
solve_helper(n - 1, true);
}
return dec_score;
}
int main() {
int n = 75;
printf("%d ", n);
solve(n, true);
printf("\n");
}
Output
75 / 25 / 5 - 4 / 2 - 1 - 0
Iterative
TBD
If you start looking for a divisor with 2, and work your way up, then the last pair of divisors you find will include the largest divisor. Alternatively you can start searching with divisor = N/2 and work down, when the first divisor found will have be largest divisor of N.
int minmoves(int n){
if(n<=3){
return n;
}
int[] dp=new int[n+1];
Arrays.fill(dp,-1);
dp[0]=0;
dp[1]=1;
dp[2]=2;
dp[3]=3;
int sqr;
for(int i=4;i<=n;i++){
sqr=(int)Math.sqrt(i);
int best=Integer.MAX_VALUE;
while(sqr >1){
if(i%sqr==0){
int fact=i/sqr;
best=Math.min(best,1+dp[fact]);
}
sqr--;
}
best=Math.min(best,1+dp[i-1]);
dp[i]=best;
}
return dp[n];
}
To test two 32-bit integers, m whose factorial is m! can be divisible by n. If it can, the function divides() returns 1, otherwise 0.
As the codes below, the problem is when m = 2010000, error happened. Could you please explain why?
#include <stdio.h>
long factorial(long n){
if((n == 0) || (n == 1)) return 1;
else{
return (n * factorial(n-1));
}
}
int divides (long n,long m)
{
long facN;
printf("n=%ld ",n);
facN = factorial(n);
if(m != 0){
if(facN == 1) return 0;
else{
if(facN % m == 0) return 1;
else if((facN % m) != 0)return 0;
}
}
else if(m == 0) return 0;
}
int main()
{
printf("%d", divides(2000000,1));
}
You need to compute the factorial with the modulus already taken into account. Using the following identity:
(a * b) % n = ((a % n) * (b % n)) % n
we can compute the factorial as:
m! % n = (((((1 % n) * 2) % n) * 3) % n) ...) % n
A 32-bit integer can only store factorials from 0 to 12.
1*2*3*4*5*6*7*8*9*10*11*12
479001600
1*2*3*4*5*6*7*8*9*10*11*12*13
6227020800
Given that 69! is of the order of 10^98 you are probably looking at value overflows but you might also be looking at running out of memory/stack as you will be nesting 2 million deep in your recursion.
Also your check if((facN % m) != 0) is redundant as it is called in the else to if(facN % m == 0)
If your cause is all about finding out whether if m! for an m is divisible by an n, do not calculate the factorial at all.
Rather split n to its factors, check if there are enough many of those inside the numbers ranging from 1 to m, inclusive.
For example; for m = 7 and n = 28, the process should be like the following:
n % 2 == 0 ? yes
n /= 2
2 * 1 <= m ? yes
n % 2 == 0 still? yes
n /= 2
2 * 2 <= m ? yes
n % 2 == 0 still? no
n % 3 == 0 ? no
...
n % 7 == 0 ? yes
n /= 7
7 <= m ? yes
n reached 1, return 1
Something like this. If you cannot manage to write this, then you probably shouldn't be dealing with that question yet. Still, if you want, leave a comment, I can edit my answer to include a working code.
I am adding a working example, using the logic above to display whether n is a divisor of m!, just to assure you that this thing does indeed work:
#include <stdio.h>
// this function basically compares the powers of the
// prime divisors of factee and divisor
// ... returns 1 if the powers in divisor are
// ... less than or equal to the powers in factee
// ... returns 0 otherwise
int divides( long factee, long divisor ){
int amount;
for ( int i = 2; i <= factee; i++ ){
if ( divisor % i )
continue;
amount = 0;
int copy = factee;
while ( copy ){
copy /= i;
amount += copy;
}
while ( divisor % i == 0 ){
if ( !amount )
return 0;
amount--;
divisor /= i;
}
if ( divisor == 1 )
return 1;
}
return 0;
}
int main( )
{
printf( "%d", divides( 20, 10000 ) );
getchar( );
return 0;
}
amount variable calculates the amount of i there are inside the m!. In the while loop in which it gets calculated, with the first cycle, the amount of is are added, then with the second cycle, the amount of i * is are added, and so on, until there aren't any.
For example, with m = 5 and i = 2, m / 2 is 2, which is the amount of occurrence of the factor 2 inside the 5!. Then m / 2 / 2, which is 1, is the amount of occurrence of the factor 2 * 2 == 4 inside the 5!. Then m / 2 / 2 == 0 is the count for 2 * 2 * 2 == 8, which causes the loop to end due to the 0 encounter.
Edit
I fixed something important in the code, removed the outermost while which was there for nothing, something I had put as I started and apparently forgot to remove, causing potential infinite-loops. Here I also made an improved version of the function that generally runs faster than the one above:
#include <stdio.h>
// this function basically compares the powers of the
// prime divisors of factee and divisor
// ... returns 1 if the powers in divisor are
// ... less than or equal to the powers in factee
// ... returns 0 otherwise
int divides( long factee, long divisor ){
int amount;
if ( divisor % 2 == 0 ){
amount = 0;
int copy = factee;
while ( divisor % 2 == 0 ){
if ( !amount ){
copy /= 2;
if ( !copy )
return 0;
amount += copy;
}
amount--;
divisor /= 2;
}
if ( divisor == 1 )
return 1;
}
for ( int i = 3; i <= factee; i += 2 ){
if ( divisor % i )
continue;
amount = 0;
int copy = factee;
while ( divisor % i == 0 ){
if ( !amount ){
copy /= i;
if ( !copy )
return 0;
amount += copy;
}
amount--;
divisor /= i;
}
if ( divisor == 1 )
return 1;
}
return 0;
}
int main( ) {
printf( "%d", divides( 34534564, 345673455 ) );
//printf( "%d", divides( 20, 10000 ) );
getchar( );
return 0;
}
long can support a value in the range of -2,147,483,647 to 2,147,483,647, here 2000000! is out of the range of long, that is why it is showing error.
I had this problem on an exam yesterday. I couldn't resolve it so you can imagine the result...
Make a recursive function: int invertint( int num) that will receive an integer and return it but inverted, example: 321 would return as 123
I wrote this:
int invertint( int num ) {
int rest = num % 10;
int div = num / 10;
if( div == 0 ) {
return( rest );
}
return( rest * 10 + invert( div ) )
}
Worked for 2 digits numbers but not for 3 digits or more. Since 321 would return 1 * 10 + 23 in the last stage.
Thanks a lot!
PS: Is there a way to understand these kind of recursion problems in a faster manner or it's up to imagination of one self?
int invertint( int num ) {
int i ;
for(i=10;num/i;i*=10);
i/=10;
if(i == 1) return num;
return( (num % 10) * i + invertint( num / 10 ) );
}
Your mistake is that in the last statement you are multiplying rest by 10. Why only 10? You need to shift the rest digit by as many digits as there are left in the remaining part of the number. You are shifting by only 1. No wonder it works only for 2-digit numbers.
The last part should be done along the lines of
int tail = invert( div );
int deg = /* number of digits in `tail` */;
return rest * (int) pow(10, deg) + div;
The problem is with return(rest * 10 + invert(div)). You can't do the multiplication yourself. The factor depends on the number of times the function is recursed, thus you have to provide the carry as a second argument to your function (carry is initialized with 0)
If you do it the other way, you won't need a counter.
int invertint(int num)
{
if (0 == num || 0 == num % 10) {
return num / 10;
}
int digits = floor(log10(num)) + 1;
int modulus = pow(10, digits - 1);
return invertint(num % modulus) * 10 + num / modulus;
}
Note that this isn't as simple as I originally thought - I had to use math.
int reverse(int no,int rev)
{
if(no!=0)
return reverse(no/10,rev*10+no%10);
else
return rev;
}
call this method as reverse(numberToReverse,0)
Just as an alternative, this could be done without recursion.
int invertint(int num)
{
int res = 0;
while (num != 0)
{
res = res * 10 + (num % 10);
num /= 10;
}
return res;
}
But since recursion was the assignment, given the int(int) signature, easiest would be with a pow(log10)) variation (provided that you're allowed to include math.h ? )
int invertint(int num)
{
if (num == 0) return 0;
return invertint(num / 10) + (int)pow(10, (int)log10(num)) * (num % 10);
}
This is the simplest approach.
int sum=0;
int reverse(int n)
{
if(n>0)
{
sum=(sum*10)+(n%10);
reverse(n/10);
}
return sum;
}
I want to write a function to round a double to an int using Banker's Rounding method (round half to even: http://en.wikipedia.org/wiki/Rounding#Round_half_to_even), like:
int RoundToInt(double x);
How can I do that?
Update:
The best I can get is this:
int RoundToInt(double x)
{
int s = (int)x;
double t = fabs(x - s);
if ((t < 0.5) || (t == 0.5 && s % 2 == 0))
{
return s;
}
else
{
if (x < 0)
{
return s - 1;
}
else
{
return s + 1;
}
}
}
But this is slow and I'm not even sure if it is accurate.
Is there some quick and accurate way to do this.
Use the standard lrint function; in the default rounding mode, it gives exactly the result you want.
double decimal = x % 1;
if(decimal < 0.5) return (int)x;
if(decimal > 0.5) return (int)x + 1;
return (int)x + ((int)x % 2 == 1 ? 1 : 0);