【学习笔记】数学知识-基本数论算法

快速幂

  • 例题
    • luogu P1226 【模板】快速幂
      • 已知 \(b\) 在二进制表示下有 \(\left\lceil \log_{2}{(b+1)} \right\rceil\) 位,设 \(c_i\) 表示其中第 \(i(1 \le i \le \left\lceil \log_{2}{(b+1)} \right\rceil)\) 位的数字,且 \(c_i \in [0,1]\),那么有 \(b=\sum\limits_{i=1}^{\left\lceil \log_{2}{(b+1)} \right\rceil}c_i 2^{i-1}\) ,于是有 \(a^b=a^{\sum\limits_{i=1}^{\left\lceil \log_{2}{(b+1)} \right\rceil}c_i 2^{i-1}}\) 。又因为 \(a^{2^i}=(a^{2^{i-1}})^2\) ,遍历 \(b\) 在二进制表示下的 \(\left\lceil \log_{2}{(b+1)} \right\rceil\) 位中满足 \(c_i=1\) 的即可。

      • 时间复杂度为 \(O(\log_{2}{b})\)

        点击查看代码
        ll qpow(ll a,ll b,ll p)
        {
        	ll ans=1;
        	while(b>0)
        	{
        		if(b&1)
        		{
        			ans=ans*a%p;
        		}
        		b>>=1;
        		a=a*a%p;
        	}
        	return ans;
        }
        int main()
        {
        	ll a,b,p;
        	cin>>a>>b>>p;
        	cout<<a<<"^"<<b<<" mod "<<p<<"="<<qpow(a,b,p);
        	return 0;
        }
        
    • luogu P5035 金坷垃 | AT_atc002_b n^p mod m | UVA374 Big Mod | UVA1230 MODEX | SP3442 LASTDIG - The last digit | SP9494 ZSUM - Just Add It

龟速乘

  • 例题
    • SP26368 PWRANDMOD - Power and Mod

      • 已知 \(b\) 在二进制表示下有 \(\left\lceil \log_{2}{(b+1)} \right\rceil\) 位,设 \(c_i\) 表示其中第 \(i(1 \le i \le \left\lceil \log_{2}{(b+1)} \right\rceil)\) 位的数字,且 \(c_i \in [0,1]\),那么有 \(b=\sum\limits_{i=1}^{\left\lceil \log_{2}{(b+1)} \right\rceil}c_i 2^{i-1}\) ,于是有 \(a \times b=a \times {\sum\limits_{i=1}^{\left\lceil \log_{2}{(b+1)} \right\rceil}c_i 2^{i-1}}\) 。又因为 \(a \times 2^i=a \times 2^{i-1} \times 2\) ,遍历 \(b\) 在二进制表示下的 \(\left\lceil \log_{2}{(b+1)} \right\rceil\) 位中满足 \(c_i=1\) 的即可。
    • 时间复杂度为 \(O(\log_{2}{b})\)

      点击查看代码
      ll read()
      {
      	ll x=0,f=1;
      	char c=getchar();
      	while(c>'9'||c<'0')
      	{
      		if(c=='-')
      		{
      			f=-1;
      		}
      		c=getchar();
      	}
      	while('0'<=c&&c<='9')
      	{
      		x=x*10+c-'0';
      		c=getchar();
      	}
      	return x*f;
      }
      void write(ll x)
      {
      	if(x<0)
      	{
      		putchar('-');
      		x=-x;
      	}
      	if(x>9)
      	{
      		write(x/10);
      	}
      	putchar((x%10)+'0');
      }
      ll smul(ll a,ll b,ll p)
      {
      	ll ans=0;
      	while(b>0)
      	{
      		if(b&1)
      		{
      			ans=(ans+a)%p;
      		}
      		b>>=1;
      		a=(a+a)%p;
      	}
      	return ans;
      }
      ll qpow(ll a,ll b,ll p)
      {
      	ll ans=1;
      	while(b>0)
      	{
      		if(b&1)
      		{
      			ans=smul(ans,a,p);
      		}
      		b>>=1;
      		a=smul(a,a,p);
      	}
      	return ans;
      }
      int main()
      {
      	ll t,a,b,p,i;
      	t=read();
      	for(i=1;i<=t;i++)
      	{
      		a=read();
      		b=read();
      		p=read();
      		write(qpow(a,b,p));
      		cout<<endl;
      	}
      	return 0;
      }
      

快速乘

  • 例题
    • luogu P10446 64位整数乘法
      • 容易有 \(a \times b \bmod p=a \times b-\left\lfloor\dfrac{ab}{p}\right\rfloor \times p\) 。接着借助 unsigned long longlong double 实现即可。 另外,因精度误差,最后得到的结果可能为负数,这就需要 \(+p\) 使之变为整数。

        • 快速乘误差较大,请谨慎使用。
      • 时间复杂度为 \(O(1)\)

        点击查看代码
        ll qmul(ll a,ll b,ll p)
        {
        	return ((ull)((ull)a*b-(ull)(1.0L*a/p*b+0.5L)*p)+p)%p;
        }
        int main()
        {
        	ll a,b,p;
        	cin>>a>>b>>p;
        	cout<<qmul(a,b,p)<<endl;
        	return 0;
        }
        
posted @ 2023-12-18 11:54  hzoi_Shadow  阅读(37)  评论(3编辑  收藏  举报
扩大
缩小