Блог пользователя Beautiful_War

Автор Beautiful_War, история, 3 года назад, По-английски

Suppose Given a expression = (a*b*c)/(x*y*z) But as the value can be very big you have to output the final value mod 100000000000031 (1 <= a, b, c, x, y, z <= 10^18)

  • Проголосовать: нравится
  • 0
  • Проголосовать: не нравится

»
3 года назад, скрыть # |
 
Проголосовать: нравится +168 Проголосовать: не нравится

»
3 года назад, скрыть # |
 
Проголосовать: нравится -56 Проголосовать: не нравится
int mult(int x,int y){ return ((x%mod)*(y%mod))%mod;}
int expo(int x,int y){
  if (y==0) return 1;
  int a=expo(x,y/2);
  a=mult(a,a);
  if (a%2) a=mult(a,x);
  return a;
}
int divide(int x,int y){ return mult(x,expo(y,mod-2));}
//divide(mult(mult(a,b),c),mult(mult(x,y),z));

Multiplication is simple. Exponentiation using binary exponantion(works in log n time). Find modular inverse of the divisor with exponantion(fermat's little theorem) and multiply with x.

»
3 года назад, скрыть # |
 
Проголосовать: нравится +62 Проголосовать: не нравится

»
3 года назад, скрыть # |
Rev. 2  
Проголосовать: нравится +40 Проголосовать: не нравится

If you don't have __int128, you can avoid overflow when multiplying long long by something similar to binpow

long long mult(long long a, long long b)
{
    if (!b) return 0;
    long long r = mult(a, b/2);
    if (b&1) return ((r+r) % mod + a) % mod;
    return (r+r)% mod;
}

But it will take $$$O(\log b)$$$

»
3 года назад, скрыть # |
 
Проголосовать: нравится +24 Проголосовать: не нравится

Since $$$10^{14} \lt 2^{57}$$$, you can use the double hack from this blog:

uint64_t prod_double(const uint64_t x, const uint64_t y, const uint64_t m) {
	uint64_t c = (double)x * y / m;
	int64_t ans = int64_t(x * y - c * m) % int64_t(m);
	if (ans < 0)
		ans += m;
	return ans;
}
»
3 года назад, скрыть # |
Rev. 4  
Проголосовать: нравится +10 Проголосовать: не нравится

You can obviously create your own BigNum structure or something but that is too much work.

Instead we can shift our look from $$$\mathbb{Z}_{M}$$$, where $$$M=10^{14}$$$, to $$$\mathbb{Z}_{\sqrt{ M }}[\sqrt{M}]$$$. We will essentially keep two parts of each number. Maintaining elements of $$$\mathbb{Z}_{\sqrt{ M }}[\sqrt{ M }]$$$ is easy since we only keep two coefficients which are less than $$$\sqrt{ M }=10^7$$$.

Specifically, if $$$x\in \mathbb{Z}_{\sqrt{ M }}[\sqrt{ M }]$$$ then there are $$$a,b\in\mathbb{Z}_{\sqrt{ M }}$$$ such that $$$x=a+b\sqrt{ M }$$$, this will represent the literal $$$a+b\sqrt{ M }$$$ number in $$$\mathbb{Z}_{M}$$$. If $$$y\in\mathbb{Z}_{M}$$$ then with division there are $$$q,r$$$ such that $$$y=q\sqrt{ M }+r$$$ with $$$0\leq r \lt \sqrt{ M }$$$ and $$$0\leq q \lt \sqrt{ M }$$$ (else we would have $$$y\geq q\sqrt{M}\geq M \gt y$$$), so this is the representation of $$$y$$$ in $$$\mathbb{Z}_{\sqrt{ M }}[\sqrt{ M }]$$$.

Now we carry out the multiplication in $$$\mathbb{Z}_{\sqrt{ M }}[\sqrt{ M }]$$$ as

$$$(a +b\sqrt{ M })(c+d\sqrt{ M })=ac+bdM+(bc+ad)\sqrt{ M }=ac+(bc+ad)\sqrt{ M }$$$

,which we can do now since the multiplications fit in long long.

Keep in mind that this technique is simple and perhaps nice, but it is not a great solution for multiplying big numbers in general.