820 字
4 分钟
[BZOJ 1409] Password
Description
Rivest是密码学专家。近日他正在研究一种数列E = {E[1],E[2],……,E[n]}, 且E[1] = E[2] = p(p为一个质数),E[i] = E[i-2]*E[i-1] (若2<i<=n)。
例如{2,2,4,8,32,256,8192,……}就是p = 2的数列。在此基础上他又设计了一种加密算法,该算法可以通过一个密钥q (q < p)将一个正整数n加密成另外一个正整数d,计算公式为:d = E[n] mod q。现在Rivest想对一组数据进行加密,但他对程序设计不太感兴趣,请你帮助他设计一个数据加密程序。
Input
第一行读入m,p。其中m表示数据个数,p用来生成数列E。 以下有m行,每行有2个整数n,q。n为待加密数据,q为密钥。 数据范围: 0 < p n< 2^31 0 < q < p 0 < m <= 5000。
Output
将加密后的数据按顺序输出到文件 第i行输出第i个加密后的数据。
Sample Input
输入样例1
2 7
4 5
4 6
输入样例2
4 7
2 4
7 1
6 5
9 3
Sample Output
输出样例1
3
1
输出样例2
3
0
1
1
题解
设斐波那契数列的第i项为
斐波那契数列
可以发现
所以我们的任务变为了求然后矩阵快速幂
最后乘上 就可以了
然后由出现了一个问题
我们需要取膜(雾)
要知道 所以我们需要欧拉定理
然后易得
使用条件是 a与p 互质
然后就可以了筛出素数 求就行了
#include <cstring>
#include <cstdio>
#include <cmath>
using namespace std;
bool isnprime[1000005];
int prime[200005], Idx;
void Get_Prime()
{
isnprime[1] = 1;
for (int i = 2; i <= 1000000; i++)
{
if (!isnprime[i])
{
prime[++Idx] = i;
}
for (int j = 1; j <= Idx; j++)
{
if (prime[j] * i > 1000000)
break;
isnprime[i * prime[j]] = 1;
if (i % prime[j] == 0)
break;
}
}
}
long long Get_Phi(long long x)
{
if (x == 1)
return 0;
int i = 1;
int Sq = sqrt(x);
long long ans = x;
while (x != 1)
{
if (prime[i] > Sq)
{
ans = ans - ans / x;
break;
}
if (x % prime[i] == 0)
{
ans = ans - ans / prime[i];
while (x % prime[i] == 0)
x /= prime[i];
}
++i;
}
return ans;
}
long long phi;
class Matrix
{
public:
int n, m;
long long a[3][3];
Matrix(int n1, int m1)
{
n = n1, m = m1;
memset(a, 0, sizeof(a));
}
Matrix operator*(const Matrix &A)
{
Matrix ans(n, A.m);
for (int i = 1; i <= n; i++)
for (int k = 1; k <= A.m; k++)
{
for (int j = 1; j <= m; j++)
ans.a[i][k] += a[i][j] * A.a[j][k];
if (ans.a[i][k] >= phi)
ans.a[i][k] = ans.a[i][k] % phi/* + phi*/;
}
return ans;
}
Matrix operator^(const long long &b)
{
long long k = b;
Matrix ans(n, m);
for (int i = 1; i <= n; i++)
{
ans.a[i][i] = 1;
}
Matrix A = *this;
while (k)
{
if (k & 1)
ans = ans * A;
k >>= 1;
A = A * A;
}
return ans;
}
};
long long pow_mod(long long a, long long b, long long mod)
{
long long ans = 1;
while (b)
{
if (b & 1)
ans = ans * a % mod;
b >>= 1;
a = a * a % mod;
}
return ans;
}
int main()
{
freopen("password.in", "r", stdin);
freopen("password.out", "w", stdout);
long long m, p;
Get_Prime();
Matrix O(2, 2);
O.a[1][1] = O.a[1][2] = O.a[2][1] = 1;
Matrix L(2, 1);
L.a[1][1] = 1;
scanf("%lld%lld", &m, &p);
while (m--)
{
long long n, q;
scanf("%lld%lld", &n, &q);
if (q == 1)
{
printf("0\n");
continue;
}
int t = p - q;
if (t == 1)
{
printf("1\n");
continue;
}
phi = Get_Phi(q);
printf("%lld\n", pow_mod(p, ((O ^ n) * L).a[2][1], q));
}
}