简体   繁体   中英

JAVA Optimal way to calculate 3^n - 3*2^n + 3.

I am trying to calculate
((3^n) - (3*(2^n)) + 3) for 1<=N<=109 in JAVA.

But it looks like it takes a lot of time to calculate this as per the problem statement.

double mul =  Math.pow(3,k);
double mul2 = Math.pow(2,k);    
double res =  ((mul - ((3* mul2)) + 3 ) % (1000000000 + 7));

The problems I am facing are

1) Time limit exceeded in java.(which should be less than 1 sec)
2) The result goes out of limit and thus provides wrong output.

Any suggestion to improve the code/calculation method will be helpful. As you can see the result to be displayed is to be modulo(1000000000 + 7). Also I have tried writing my own power function in which I am doing this modulo after every multiplication, which does not help either.

Thanks

Abstain from using BigIntegers and evaluating powers from scratch, this is the naïve and inefficient approach.

Do work incrementally using modular arithmetic.

Keep two integer variables holding the values of Aₙ:= 3ⁿ mod 1000000007 and Bₙ:= 3×2ⁿ mod 1000000007 .

The updates are obvious: Aₙ₊ₗ= 3×Aₙ mod 1000000007 and Bₙ₊ₗ= 2×Bₙ mod 1000000007 .

For the modulo operations, I recommend to use comparisons instead of % .

You are lucky that 2×1000000007 fits in a 32 bits signed integer. But not 3×1000000007 , so I recommend to perform the multiplies by 3 as two additions.

Thus, all you have to implement is integer addition and subtraction modulo 1000000007 .

private static int sum(int x, int y)
{
    return x >= 1000000007 - y ? x - (1000000007 - y) : x + y;
}

private static int sub(int x, int y)
{
    return x < y ? x + (1000000007 - y) : x - y;
}

int n;
int a= 1;
int b= 3;
for (n= 1; n <= 109; n++)
{
    a= sum(sum(a, a), a);
    b= sum(b, b);
    int res= sum(sub(a, b), 3);
}

The problem is JAVA independent , you need to find a^b efficiently for large b . You can do this by using modular exponentiation , complexity is O(log(b)) .

  long long power(long long a,long long b)
  {
        if(b==0)return 1;
        long long ans=power(a,b/2);
        ans=(ans*ans)%1000000007;
        if(b%2)ans=(ans*a)%1000000007;
        return ans;
  }

The above is in c/c++ , same logic can be extended in JAVA.
EDIT
Now as you need to do this for 1<=N<=109 the complexity would increase as compared to linear fashion. To avoid this look at what we have to calculate.

  1. The first term makes a GP 3 , 9 ,....3^(109) so you can just replace it by 3(3^(109)-1)/2 , so just calculate 3^(109) MOD 1000000007 once by calling the power function.(You would need to calculate MOD inverse of 2 also) .So this takes O(log(109)).
  2. The second term is also a GP and can be done in a similar way.
  3. The last term is just 3*109

You may use the BigInteger class for better precision. eg

private static final BigInteger TWO = new BigInteger("2");
private static final BigInteger THREE = new BigInteger("3");

//input n, m (modulo)
public static BigInteger getResult(BigInteger n, BigInteger m) {
    BigInteger a = THREE.modPow(n, m);
    BigInteger b = TWO.modPow(n, m);

    return a.subtract(THREE.multiply(b)).add(THREE).mod(m);

}

*If you use it inside a for loop, you may gain some advantage from precomputations, as every next n may use the results of the previous n-1 calculations. Eg 3^n could be computed as 3^(n-1)*3

You face two issues, both can be adressed by using BigInteger. First, BigInteger is capable of holding your values and secondly it already implements a method to perform modular exponentiation namley:

BigInteger  modPow(BigInteger exponent, BigInteger m)

which returns a BigInteger whose value is (this^exponent mod m).

If you are interested on the other hand, why it doesn't work (ie is too slow) I would recommend you the following article explaining efficent integer exponention article

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM