码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2017-07-30 22:05:22      阅读:187      评论:0      收藏:0      [点我收藏+]

标签:bsp   space   one   print   bre   mat   不用   efi   read   

读了一下题就会很愉快的发现,这个数列是关于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 数论(扩展欧拉+矩阵快速幂+快速幂)

标签:bsp   space   one   print   bre   mat   不用   efi   read   

原文地址:http://www.cnblogs.com/TSHugh/p/7260414.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!