A bit of help with problem ZDI did not anticipate it at first, but it turns out that problem ZD has a nasty overflow problem. If you try to use the powmod() function from the provided number.cpp, it will fail because the line "r *= r;" will try to square a number that is slightly larger than 232. There is a rather ugly fix to this. Try using this powmod() function instead of the one from the collection of number theoretic algorithms.
typedef unsigned long long ull;
/**
* Multiplies two numbers and returns the product modulo n
* ull is unsigned long long
**/
ull multmod( ull a, ull b, ull n )
{
ull a0 = a & 0xFFFFFFFFLL;
ull a1 = a >> 32;
ull b0 = b & 0xFFFFFFFFLL;
ull b1 = b >> 32;
/**
* The point of the 4 lines above is to make
* a = a0 + ( a1 << 32 );
* b = b0 + ( b1 << 32 );
* Now expand
* a * b = ( a0 + ( a1 << 32 ) )
* * ( b0 + ( b1 << 32 ) )
* into 4 terms and evaluate each one modulo n.
* The assumption here is that a, b and n are only
* slightly bigger than ( 1 << 32 ).
**/
// The a0 * b0 term
ull ans = ( a0 * b0 ) % n;
// The a0 * b1 * 2^32 term [ = ( a0 * ( 2^32 - 1 ) + a0 ) * b1 ]
ans += ( ( ( ( a0 * 0xFFFFFFFFLL ) % n ) + a0 ) * b1 ) % n;
// The a1 * 2^32 * b0 term [ = ( b0 * ( 2^32 - 1 ) + b0 ) * a1 ]
ans += ( ( ( ( b0 * 0xFFFFFFFFLL ) % n ) + b0 ) * a1 ) % n;
// The a1 * b1 * 2^64 term [ = ( ( 2^64 - 1 ) + 1 ) * a1 * b1 ]
ans += ( ( ( ( ( ( ull )0xFFFFFFFFFFFFFFFFLL % n ) + 1 ) * a1 ) % n ) * b1 ) % n;
return ans % n;
}
ull powmod( ull b, ull p, ull m )
{
ull r = 1;
for( ull i = ( ( ull )1 << 63 ); i; i >>= 1 )
{
r = multmod( r, r, m );
if( p & i ) r = multmod( r, b, m );
}
return r;
}
|