(fast power algorithm + high precision) rogue P1045 Mason number

Posted by thinkmarsh on Fri, 10 Dec 2021 12:40:11 +0100

preface

At the end of the story, let's end with a very classic topic - "Mason number". Accept that there will always be high-precision operations we haven't prepared. Of course, we can prepare high-precision fast power templates in advance, but there will always be a time when there will be a lot of secrets. Even if there is an unprecedented type of high-precision operation, we should make a reasonable response.

Topic overview

AC code

#include<iostream>
#include<cstring>
#include<cmath>
using namespace std;
#define maxn 1002
int mid[maxn],base[maxn],ans[maxn];
void qpower()//Replacing the multiplication part of low precision fast power algorithm 
{
	memset(mid,0,sizeof(mid));
	for(int i=1;i<=500;++i)
	  for(int j=1;j<=500;++j)
	  mid[i+j-1]+=ans[i]*base[j];
 for(int i=1;i<=500;++i)
   mid[i+1]+=mid[i]/10,mid[i]%=10;
 memcpy(ans,mid,sizeof(mid));
}
void grow()//Replace the self square part of base in low precision fast power algorithm 
{
	memset(mid,0,sizeof(mid));
	for(int i=1;i<=500;++i)
	  for(int j=1;j<=500;++j)
	  	mid[i+j-1]+=base[i]*base[j];
	for(int i=1;i<=500;++i)
	mid[i+1]+=mid[i]/10,mid[i]%=10;
	memcpy(base,mid,sizeof(base));
}
int main()
{
	int p;
	scanf("%d",&p);
	printf("%d\n",(int)(log10(2)*p+1));
	ans[1]=1,base[1]=2;//ans stores the answer, and base stores the number of times accumulated in the fast power algorithm 
	while(p>0)//Counting  
	{
		if(p&1)
		qpower();
		grow();
		p>>=1;
	}
	int sum=0;
	ans[1]-=1;//The end of the power of 2 will not be 0. You can directly subtract 1 without considering the problem of borrowing
	//(because if you want to come out with 0, the previous end must be 5, which is obviously impossible) 
	for(int i=500;i>=1;--i)
	{
		printf("%d",ans[i]);
		++sum;
		if(sum%50==0)
		printf("\n"); 
	}
  return 0;
}

Analysis ideas

1. First of all, you may think of using a simple method, because there is a storage length in the large integer class, and then multiply 2 by p times, but there are two problems. One is that the time complexity reaches O(n) The other is that the title implies that the last digit may be very large, and the array does not have so many digits, so we can no longer use the Bigint template for this question, but we should implement a more efficient power operation ourselves. And we only need the last 500 digits. Therefore, we should memorize the template at the beginning, but the more we do later, we can no longer be limited by the template "No move wins with move".

2. How is the fast power algorithm implemented? For example 2 10 2^{10} 210. The simple way is to multiply 10 times, but do we need it? Think about our own calculation, we use it directly 2 5 ∗ 2 5 2^5*2^5 25 * 25, if 2 5 2^5 25 or not? Then consider using a smaller power. The idea of fast power is similar to this. Start exponential expansion from a small power, which greatly reduces the complexity. In fact, the time complexity of fast power algorithm is o( l o g n log_n logn). This can be used in many topics for optimization. Generally, for a low precision fast power a b a^b AB (because the power operation will be very large, the template also adds the operation of remainder k), which has the following methods:

#define ll long long
ll qpower(ll a,ll b)
{
	ll base=a,ans=1;
	while(b>0)
	{
		if(b&1)
		{
		ans*=base;
	  	ans%=k;
	  }
	  base*=base;
	  base%=k;
	  b>>=1;
	}
	return ans;
}

In which "b > > 1" is actually used to check whether the current bit is available through binary. That is to say, in fact, it is done by checking whether there is a current bit first a 1 a^1 a1, check again a 2 a^2 a2, check again a 4 . . . a^4... a4... If so, multiply them. The end condition is that b is all 0 in binary, that is, all decomposition is completed. What about high-precision? This requires high-precision multiplication and high-precision. The corresponding replacement is written in the comment line, which will not be repeated here.

3. How to calculate the number of bits (without high-precision Bigint storage length)? First, 2 p − 1 2^p-1 The number of digits of 2p − 1 is equal to 2 p 2^p The number of digits to the power of 2p. Why? Because 2 p 2^p The end of 2p will not be 0, so it is impossible to say that subtracting 1 reduces the number of digits. Then why can't the last bit be 0? Because the last bit is 0, then 2 p − 1 2^{p-1} 2p − 1 has to end with 5, which contradicts that it is an even number. Secondly, we know that, 1 0 n 10^n 10n yes n + 1 n+1 n+1 bit. Then, there is the following deformation: (the finger pair transformation method of high school is used)
2 p = 1 0 l o g 10 2 p 2^p={10^{log_{10}2}}^p 2p=10log10​2p
Therefore, its digits are:
l o g 10 2 p + 1 = p ∗ l o g 10 2 + 1 log_{10}2^p+1=p*log_{10}2+1 log10​2p+1=p∗log10​2+1

4. The last is the output format. Remember to subtract 1 from the last bit without considering borrowing. The reason is the same as the length analysis. If you are afraid that the line feed is unclear with i, set another counter and change it at 50.

5. If you can't multiply high precision by high precision, you can take a look at this question. A*B problem, high precision times high precision
6. The last topic is to say that although high-precision is a question type with strong template nature, we can't just rely on the template. We should really deeply understand the method of "analog manual operation + carry" of high-precision, so that we can temporarily realize the operation we haven't memorized.

Advertisement at the end of the article

Learning algorithms and data structures is really a tiring process. If you can't do it, you can only turn to problem solving. Because writing code is basically a thousand people and a thousand faces. At the same time, many problem solving are found on the Internet. Either you use the knowledge you haven't learned and can't understand it; or the internal core is too simple and can only fool the current problem, which is not universal.

If you are a student who likes to do the topics of Luogu, ACwing and PTA, you are welcome to pay attention to my blog. I mainly do the topics on these three platforms. I will write and publish the solutions for the topics that are valuable and difficult.
Previous articles by TreeTraverler

Topics: C++ Algorithm