【bzoj1409】Password 线性筛法+矩阵乘法

E[i]=p^f[i]
f[i]表示斐波那契数列的第i项
E[i]%q
=p^f[i]%q
因为q<p,所以gcd(p,q)=1
所以p^phi(q)%q=1,注意q不一定是质数
先求f[i]%phi(q)的值,再用快速幂求值即可

按理说,用O(√n)的做法求phi,但是貌似卡不过去,那么直接枚举素数分解质因数就好了

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<iostream>
#define maxn 100010

using namespace std;

int phi;

struct matrix
{
	int a[3][3];
	int x,y;
	matrix operator*(matrix b)
	{
		matrix ans;
		memset(ans.a,0,sizeof(ans.a));
		ans.x=x;ans.y=b.y;
		for (int i=1;i<=ans.x;i++)
	 	  for (int j=1;j<=ans.y;j++)
	 	     for (int k=1;k<=y;k++)
	      		ans.a[i][j]=((long long)ans.a[i][j]+(long long)a[i][k]*b.a[k][j]%phi)%phi;
		return ans;
	}
}a,b;

int prime[maxn];
bool vis[maxn];
int tot,n,ans,p,T,q;

int power(int x,int y,int mod)
{
	int ans=1;
	while (y)
	{
		if (y&1) ans=(long long)ans*x%mod;
		x=(long long)x*x%mod;
		y>>=1;
	}
	return ans%mod;
}

int cal(int x)
{
	int ans=x;
	for (int i=1;i<=tot && (long long)prime[i]*prime[i]<=x;i++)
	  if (x%prime[i]==0)
	  {
	  	while (x%prime[i]==0) x/=prime[i];
	  	ans=ans/prime[i]*(prime[i]-1);
	  }
	if (x!=1) ans=ans/x*(x-1); 
	return ans;
}

int calc(int x)
{
	x--;
	b.x=1;b.y=2;
	b.a[1][1]=1;b.a[1][2]=0;
	a.x=2;a.y=2;
	a.a[1][1]=1;a.a[1][2]=1;
	a.a[2][1]=1;a.a[2][2]=0;
	while (x)
	{
		if (x&1) b=b*a;
		a=a*a;
		x>>=1;
	}
	return b.a[1][1];
}

int main()
{
	scanf("%d%d",&T,&p);
	n=100000;
	for (int i=2;i<=n;i++)
	{
		if (!vis[i]) prime[++tot]=i;
		for (int j=1;j<=tot && i*prime[j]<=n;j++)
		{
			vis[i*prime[j]]=1;
			if (i%prime[j]==0) break;
		}
	}
	while (T--)
	{
		scanf("%d%d",&n,&q);
		phi=cal(q);
		printf("%d\n",power(p,calc(n),q));
	}
	return 0;
}


你可能感兴趣的:(【bzoj1409】Password 线性筛法+矩阵乘法)