• [BZOJ1409]Password


    [BZOJ1409]Password

    试题描述

    Rivest 是密码学专家。近日他正在研究一种数列 (E = {E[1],E[2], cdots ,E[n]}),且 (E[1] = E[2] = p)(p) 为一个质数),(E[i] = E[i-2] imes E[i-1])(若 (2 < i le n))。

    例如 ({2,2,4,8,32,256,8192,cdots}) 就是 (p = 2) 的数列。在此基础上他又设计了一种加密算法,该算法可以通过一个密钥 (q (q < p)) 将一个正整数 (n) 加密成另外一个正整数 (d),计算公式为:(d = E[n] mod q)。现在 Rivest 想对一组数据进行加密,但他对程序设计不太感兴趣,请你帮助他设计一个数据加密程序。

    输入

    第一行读入 (m)(p) 。其中 (m) 表示数据个数,(p) 用来生成数列 (E)。 以下有 (m) 行,每行有 (2) 个整数 (n)(q)(n) 为待加密数据,(q) 为密钥。

    输出

    将加密后的数据按顺序输出到文件 第 (i) 行输出第 (i) 个加密后的数据。

    输入示例1

    2 7
    4 5
    4 6
    

    输出示例1

    3
    1
    

    输入示例2

    4 7
    2 4
    7 1
    6 5
    9 3
    

    输出示例2

    3
    0
    1
    1
    

    数据规模及约定

    (0 < p, n< 2^{31})(0 < q < p)(0 < m le 5000)

    题解

    欧拉定理:对于 (gcd(n, a) = 1) 的数对 (n, a),满足 (a^{varphi(n)} equiv 1 (mod n))。(其中 (varphi(n)) 表示欧拉函数,即 (1 sim n) 中与 (n) 互质的数的个数)

    知道这个定理,做法就显然了。

    由于 (q < p),且 (p) 是质数,那么 (gcd(p, q) = 1),从而 (p^{varphi(q)} equiv 1 (mod q)),这样,(p) 的整数次幂就是以 (varphi(q)) 为长度循环的了,所以对于指数可以直接对 (varphi(q)) 取模。

    指数是什么呢?正好就是斐波那契数列错了一位,矩阵快速幂即可。

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cctype>
    #include <algorithm>
    using namespace std;
    #define rep(i, s, t) for(int i = (s), mi = (t); i <= mi; i++)
    #define dwn(i, s, t) for(int i = (s), mi = (t); i >= mi; i--)
    
    int read() {
    	int x = 0, f = 1; char c = getchar();
    	while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); }
    	while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); }
    	return x * f;
    }
    
    #define maxn 47010
    #define LL long long
    
    bool vis[maxn];
    int prime[maxn], cp;
    void init() {
    	int n = maxn - 1;
    	rep(i, 2, n) {
    		if(!vis[i]) prime[++cp] = i;
    		for(int j = 1; j <= cp && i * prime[j] <= n; j++) {
    			vis[i*prime[j]] = 1;
    			if(i % prime[j] == 0) break;
    		}
    	}
    	return ;
    }
    
    int MOD;
    struct Matrix {
    	int A[2][2];
    	Matrix() {}
    	Matrix operator * (const Matrix& t) const {
    		Matrix ans;
    		ans.A[0][0] = ((LL)A[0][0] * t.A[0][0] + (LL)A[0][1] * t.A[1][0]) % MOD;
    		ans.A[0][1] = ((LL)A[0][0] * t.A[0][1] + (LL)A[0][1] * t.A[1][1]) % MOD;
    		ans.A[1][0] = ((LL)A[1][0] * t.A[0][0] + (LL)A[1][1] * t.A[1][0]) % MOD;
    		ans.A[1][1] = ((LL)A[1][0] * t.A[0][1] + (LL)A[1][1] * t.A[1][1]) % MOD;
    		return ans;
    	}
    	Matrix operator *= (const Matrix& t) { *this = *this * t; return *this; }
    } base, tr;
    Matrix PowM(Matrix a, int b) {
    	Matrix ans = a, t = a; b--;
    	while(b) {
    		if(b & 1) ans *= t;
    		t *= t; b >>= 1;
    	}
    	return ans;
    }
    
    int Pow(int a, int b, int m) {
    	int ans = 1, t = a;
    	while(b) {
    		if(b & 1) ans = (LL)ans * t % m;
    		t = (LL)t * t % m; b >>= 1;
    	}
    	return ans;
    }
    
    int main() {
    	init();
    	int T = read(), p = read();
    	tr.A[0][0] = 0;
    	tr.A[0][1] = tr.A[1][0] = tr.A[1][1] = 1;
    	while(T--) {
    		int n = read(), q = read(), phi = q, tmp = q;
    		if(n <= 2){ printf("%d
    ", p % q); continue; }
    		rep(i, 1, cp) {
    			if(tmp % prime[i] == 0) {
    				phi = phi / prime[i] * (prime[i] - 1);
    				while(tmp % prime[i] == 0) tmp /= prime[i];
    			}
    			if(tmp == 1) break;
    		}
    		if(tmp > 1) phi = phi / tmp * (tmp - 1);
    		MOD = phi;
    		base.A[0][0] = base.A[1][0] = 1;
    		base.A[0][1] = base.A[1][1] = 0;
    		base = PowM(tr, n - 1) * base;
    		printf("%d
    ", Pow(p % q, base.A[0][0], q) % q);
    	}
    	
    	return 0;
    }
    
  • 相关阅读:
    控件的Visible设为false后,ViewState是否visible?
    协议森林02 小喇叭开始广播 (以太网与WiFi协议)
    Python深入02 上下文管理器
    信号与频谱
    飓风“桑迪”路径图的制作
    谁动了我的奶酪?
    协议森林01 邮差与邮局 (网络协议概观)
    协议森林04 地址耗尽危机 (IPv4与IPv6地址)
    协议森林03 IP接力赛 (IP, ARP, RIP和BGP协议)
    Python补充03 Python内置函数清单
  • 原文地址:https://www.cnblogs.com/xiao-ju-ruo-xjr/p/8509106.html
Copyright © 2020-2023  润新知