BZOJ 1409 Password 数论(扩展欧拉+矩阵快速幂+快速幂)

Posted TS_Hugh

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ 1409 Password 数论(扩展欧拉+矩阵快速幂+快速幂)相关的知识,希望对你有一定的参考价值。

读了一下题就会很愉快的发现,这个数列是关于p的幂次的斐波那契数列,很愉快,然后就很愉快的发现可以矩阵快速幂一波,然后再一看数据范围就......然后由于上帝与集合对我的正确启示,我就发现这个东西可以用欧拉函数降一下幂,因为两个数一定互质因此不用再加一个phi(m),于是放心的乘吧宝贝!!

#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <iostream>
#include <cmath>
#define r register
using namespace std;
typedef long long LL;
inline LL read()
{
  r LL sum=0;
  r char ch=getchar();
  while(ch<0||ch>9)ch=getchar();
  while(ch>=0&&ch<=9)
  {
    sum=(sum<<1)+(sum<<3)+ch-0;
    ch=getchar();
  }
  return sum;
}
LL prime[600000];
bool isnot[600000];
LL T;
LL temp_a[4][4],a[4][4],b[4],temp_b[4];
LL m,p;
inline void Init()
{
  for(r LL i=2;i<=(1<<16);i++)
  {
    if(!isnot[i])
      prime[++T]=i;
    for(r LL j=1;j<=T&&prime[j]*i<=(1<<17);j++)
    {
      isnot[prime[j]*i]=1;
      if(i%prime[j]==0)break;
    }
  }
  m=read(),p=read();
}
inline LL Opha(LL x)
{
  r LL to=(LL)sqrt(x+0.5);
  r LL ans=x;
  for(r LL i=1;prime[i]<=to;i++)
  if(x%prime[i]==0)
  {
    ans=ans/prime[i]*(prime[i]-1);
    while(x%prime[i]==0)x/=prime[i];
  }
  if(x!=1)
    ans=ans/x*(x-1);
  return ans;
}
inline void Multi_One(LL k)
{
  memset(temp_b,0,sizeof(temp_b));
  for(int i=1;i<=2;i++)
    for(int j=1;j<=2;j++)
      temp_b[i]=(temp_b[i]+a[i][j]*b[j]%k)%k;
  memcpy(b,temp_b,sizeof(b));
}
inline void Multi_Two(LL K)
{
  memset(temp_a,0,sizeof(temp_a));
  for(int i=1;i<=2;i++)
    for(int j=1;j<=2;j++)
      for(int k=1;k<=2;k++)
        temp_a[i][j]=(temp_a[i][j]+a[i][k]*a[k][j]%K)%K;
  memcpy(a,temp_a,sizeof(a));
}
inline LL POW(LL x,LL k)
{
  a[1][1]=1%k,a[1][2]=1%k,a[2][1]=1%k,a[2][2]=0;
  b[1]=1%k,b[2]=0;
  while(x)
  {
    if(x&1)Multi_One(k);
    x>>=1,Multi_Two(k);
  }
  b[1]%=k;
  return b[1];
}
inline LL Pow(LL x,LL y,LL k)
{
  LL ans=1%k;
  while(y)
  {
    if(y&1)ans=ans*x%k;
    y>>=1,x=x*x%k;
  }
  ans%=k;
  return ans;
}
inline void Work()
{
  while(m--)
  {
    r LL n=read(),q=read();
    r LL x=Opha(q);
    r LL y=POW(n-1,x);
    printf("%lld\n",Pow(p,y,q));
  }
}
int main()
{
  Init();
  Work();
  return 0;
}

 

以上是关于BZOJ 1409 Password 数论(扩展欧拉+矩阵快速幂+快速幂)的主要内容,如果未能解决你的问题,请参考以下文章

[BZOJ 1409] Password

bzoj 1409 Password

『扩欧简单运用』

bzoj 3560 DZY Loves Math V - 线性筛 - 数论 - 扩展欧几里得算法

洛谷P1082 同余方程 数论

bzoj3884: 上帝与集合的正确用法(数论)